Analysis of Data Quality
To begin our analysis of data quality, let’s load our data.
ViolationsData <- read.csv(file="inspection.csv", header=TRUE, sep=",", as.is=TRUE)
In order to more easily work with our data let’s ensure that every date is in a date format rather than a string and every string is a factor variable.
library(dplyr)
library(tidyr)
##Date conversion
ViolationsData <- ViolationsData %>%
mutate(INSPECTION.DATE= as.Date(INSPECTION.DATE, format= "%m/%d/%Y"))%>%
mutate(GRADE.DATE= as.Date(GRADE.DATE, format= "%m/%d/%Y"))%>%
mutate(RECORD.DATE= as.Date(RECORD.DATE, format= "%m/%d/%Y"))
##Factor conversion
ViolationsData <- ViolationsData %>%
mutate(CUISINE.DESCRIPTION= as.factor(CUISINE.DESCRIPTION))%>%
mutate(BORO= as.factor(BORO))%>%
mutate(VIOLATION.CODE= as.factor(VIOLATION.CODE))%>%
mutate(CRITICAL.FLAG= as.factor(CRITICAL.FLAG))%>%
mutate(GRADE= as.factor(GRADE))%>%
mutate(INSPECTION.TYPE= as.factor(INSPECTION.TYPE))
Many of the questions we are interested in answering involve trends across restuarant locations. We first checked to see the number of restuarant inspections by borough. From the plot below, we noticed that there were a number of inspections in which the Borough information was missing and won’t help our analysis.
library(ggplot2)
boroughPlot <- ggplot(ViolationsData, aes(BORO, fill=BORO))
boroughPlot + geom_bar()+ theme(legend.position="none") +
ggtitle('Inspection Count by Borough') +
labs(x = "Borough", y ="Number of Inspections")
Another main feature of our data set is the inspection year since we wish to explore patters in inspection grades/scores over the years. From the plot below, we noticed that there is almost no inspection data before 2013 and surprisingly more inspection data in 1900 than 2012 and 2011. We decided to only work with data from 2013 and up. It is important to note that the number of inspections for 2017 is low since the 2017 data is only available from January - March.
violationYearsPlot <- ggplot(ViolationsData, aes(factor(as.numeric(format(INSPECTION.DATE, '%Y'))), fill="Red"))
violationYearsPlot + geom_bar()+coord_flip()+ theme(legend.position="none") +xlab("Inspection Year")+ylab("Inspection Counts") + ggtitle("Inspection Count by Year")

Another crucial feature of our data set is grade a restaurant received after inspection. We decided to plot a stacked bar chart for to see the count of each type of grade for every cuisine. We used a stacked bar chart because we wanted to quickly assess the magnitude missing without taking up extra room. From the plot below, it was shocking to see that we generally had more missing grades than grades. This was true regardlss of cuisine. It was also interested that the grades were purely missing and not categorized as “Not Yet Graded”.
ggplot(ViolationsData, aes(CUISINE.DESCRIPTION, fill = GRADE)) + geom_bar() +
coord_flip()+ggtitle("stacked bar chart of grade distributions across cuisines")

To stay on the topic of grades, after researching the letter grading program, we found the following information: + A score of less than 14 points on either initial or re-inspection results in an “A” grade + On re-inspection, a score of 14-27 points means a restaurant receives both a “B” grade and a “Grade Pending” card. + On re-inspection, a score of 28 or more points means a restaurant receives both a “C” grade and a “Grade Pending” card.
Both Z and P represent grade pending, however P represents a Grade Pending issued on re-opening following an initial inspection that resulted in a closure.
We also discovered that not every inspection is “gradable”. Gradable inspections have the following properties:
- INSPECTION TYPE in (Cycle Inspection/Initial Inspection, Cycle Inspection/Re-Inspection, Pre-Permit (Operational)/Initial Inspection, Pre-Permit (Operational)/Re-Inspection)
- ACTION in (Violations were cited in the following area(s), No violations were recorded at the time of this inspection, Establishment Closed by DOHMH)
- INSPECTION DATE > July 26, 2010
This can probably explain a fair amount of the missing grade data observed in our plot.
According to the ABOUT the data set page: The SCORE and GRADE fields may be inconsistent with each other because of limitations or errors in the data systems. That is to say, scores of 0-13, 14-27 and 28+ are not always accompanied by A, B and C grades, respectively, when they should be. There may also be cases where a grade card was given out but a record of that grade issuance is missing from the data system, and therefore missing from this dataset, even though the SCORE field is populated. Note that when initial inspections are adjudicated down to the A range, the absence of an accompanying grade associated with that inspection is correct, because the grade would not be assigned until the re-inspection is performed.
To gain some final insight on the data quality, we decided to plot the relationshp between the number of missing scores by grade and by whether or not a violation was reported. We transformed the actions taken into three categories: 1. No violations were recorded at the time of this inspection to No Violation 2. Any action reported to Violation reported 3. Missing actions to NA We then counted if the score was provided or not.
library(dplyr)
library(tidyr)
score_grade <- ViolationsData[ -c(1:9, 11:13, 16:18) ]
score_grade[score_grade == ''] <- NA
score_grade_combos <- score_grade %>% mutate(missing_score = ifelse(is.na(SCORE), "yes", "no"))
score_grade_missing <- count(score_grade_combos, c('GRADE', 'missing_score', 'ACTION'))
score_grade_missing <- score_grade_missing %>%
mutate(violation = ifelse(ACTION == 'No violations were recorded at the time of this inspection.',
"No violation",
ifelse(is.na(score_grade_missing$ACTION), NA, "Violation Reported"))) %>%
select(-c(ACTION))
ggplot(score_grade_missing, aes(x = GRADE, y = log(freq), fill = missing_score)) +
geom_bar(stat = 'identity', position = 'dodge') + facet_wrap(~violation) +
ggtitle("Grade and missing score combinations by violation report") +
labs(x = "Grade", y = "Log(Frequency)")

Interesting insights from plot above are:
Grades of NA reported high frequency of score in both No violation and violation reported category.
At first, it appears that high scores are related to low grades or needs grading but then we find restaurants with a grade of A that has the same score as a restaurant with a grade of C.
Another insight by just looking at the data is we surprisingly saw that restaurants with a critical flag still receive grades of A.This needs further analysis. SHOULD WE MAKE A PLOT FOR THIS????
Main Analysis
After analyzing the quality of the data set, we got rid of data in which the Borough is missing and the year is before 2013.
ViolationsData <- ViolationsData %>% filter (BORO != "Missing")
ViolationsData <- ViolationsData %>% filter(
as.numeric(format(INSPECTION.DATE , '%Y')) > 2012)
Now we can get a better picture of the total number of inspections by year and borough.
boroughPlot <- ggplot(ViolationsData, aes(BORO,fill=BORO))
boroughPlot + geom_bar() + theme(legend.position="none") +
facet_wrap(~factor(as.numeric( format(INSPECTION.DATE , '%Y')))) +
ggtitle("Total Inspections from 2013-2017 in each Borough") +
xlab("Borough") + ylab("Number of Inspections") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

After 2013, there seems to be a consistent amount of inspections acros the years. The number of inspections by borough also seems to make sense since we expect Manhattan to have the largest number of restuarants.
Next, we took a look at the grade distribution by borough.
inspection_grades <- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET, -ZIPCODE, -PHONE, -ACTION, -VIOLATION.CODE, -VIOLATION.DESCRIPTION, -CRITICAL.FLAG, -SCORE, -GRADE.DATE, -RECORD.DATE, -INSPECTION.TYPE,-CUISINE.DESCRIPTION)
inspection_grades_woyear<-inspection_grades %>% select(-INSPECTION.DATE)
inspection_grades_woyear <- inspection_grades_woyear %>% gather(key, value, -BORO) %>% group_by(BORO, key, value) %>% tally %>% spread(value, n, fill = 0)# %>% gather(blah, -BORO, -key) #summarize(aprop = A/(A+B+C+))
names(inspection_grades_woyear)[names(inspection_grades_woyear)=="key"] <- "grade"
names(inspection_grades_woyear)[names(inspection_grades_woyear)==""] <- "unknown"
inspection_grades_woyear <- inspection_grades_woyear %>% gather(key, value, -BORO,-grade)
RelFreq<-function(m){
((m )/sum(m))
}
inspection_grades_woyear<-inspection_grades_woyear %>% group_by(BORO,grade) %>%
mutate(percentage = (value/sum(value))*100)
ggplot(inspection_grades_woyear, aes(BORO, percentage ,fill= key)) +
geom_bar(stat="identity", position = "dodge") +
ggtitle('%Grade distribution across boroughs') +
labs(x = "boroughs", y ="percentage")+guides(fill=guide_legend(title="Grade"))

We initially hypothesized that we would see a pattern in grade distribution by borough, however, the plot shows us that grade distributions are almost the same regardless of borough.
inspection_grades_year<-inspection_grades%>% mutate(year=factor(as.numeric(format(INSPECTION.DATE , '%Y'))))
inspection_grades_year<-inspection_grades_year%>% select(-INSPECTION.DATE)
inspection_grades_year <- inspection_grades_year %>% gather(key, value, -BORO,-year) %>% group_by(BORO,year, key, value) %>%
tally %>% spread(value, n, fill = 0)# %>% gather(blah, -BORO, -key) #summarize(aprop = A/(A+B+C+))
names(inspection_grades_year)[names(inspection_grades_year)=="key"] <- "grade"
names(inspection_grades_year)[names(inspection_grades_year)==""] <- "unknown"
inspection_grades_year <- inspection_grades_year %>% gather(key, value, -BORO,-grade,-year)
RelFreq<-function(m){
((m )/sum(m))
}
inspection_grades_year<-inspection_grades_year %>% group_by(BORO,grade,year) %>%
mutate(percentage = (value/sum(value))*100)
ggplot(inspection_grades_year, aes(BORO, percentage ,fill= key)) +
geom_bar(stat="identity", position = "dodge") +facet_wrap(~year,nrow=2,ncol=3)+
guides(fill=guide_legend(title="Grade"))+
ggtitle("%Grade distribution by BOROUGH")

Adding year to this analysis showed us an increase in the proportian of As in Sataten Island in 2015 but seemed consistent throughout the rest of the plot.
We decided that borough may be too general and thus looked at grade distribution by zip code across the various years. We used a heat map to do so.
library(viridis)
nonYearDataForHeatMap<-ViolationsData %>% select(GRADE,ZIPCODE)
#nonYearDataForHeatMap<-nonYearDataForHeatMap%>%mutate(gradeYear=as.numeric(format(GRADE.DATE , '%Y')))
nonYearDataForHeatMap <- nonYearDataForHeatMap %>% group_by(GRADE,ZIPCODE) %>% tally
RelFreq<-function(m){
((m )/sum(m))
}
nonYearDataForHeatMap<- nonYearDataForHeatMap %>% group_by(ZIPCODE)%>%
mutate(percentage = (n/sum(n))*100)
ggplot(nonYearDataForHeatMap, aes(GRADE,
ZIPCODE, fill = percentage)) +
geom_tile() +
scale_fill_viridis() +
#facet_wrap(~BORO)
ggtitle("Percentage grade distribution by zipcode across years\n ")+
theme(axis.text.x=element_text(angle=-45, hjust=.1),
plot.title=element_text(margin=margin(b=.5), size = 15))+ylab("Grade")

DISCUSS WITH LAKSHYA
The next part of our analysis was to look at the average scores of each cuisine. With this information, we can help consumers see what kinds of establishments have the best and worst scores on average. This in term can help a consumer choose a type of cuisine when they are hungry.
average_scores <- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET, -ZIPCODE,
-PHONE, -INSPECTION.DATE, -ACTION,
-VIOLATION.CODE, -VIOLATION.DESCRIPTION,
-CRITICAL.FLAG, -GRADE, -GRADE.DATE,
-RECORD.DATE, -INSPECTION.TYPE)
average_cuisine <- average_scores %>% group_by(CUISINE.DESCRIPTION) %>% na.omit %>%
summarize(average_score = mean(SCORE))
average_cuisine <- arrange(average_cuisine, -average_score)
ggplot(average_cuisine, aes(reorder(x = CUISINE.DESCRIPTION, --average_score), average_score, fill = CUISINE.DESCRIPTION)) + geom_bar(stat='identity') + coord_flip() + theme(legend.position = 'none')+ggtitle("Average score across cuisines")+xlab("Cuisine description")+ylab("average score")+geom_text(aes(label = sprintf("%.2f", average_score)),position=position_stack(vjust=0.5),
vjust = 0.5, size = 3)

worst10 <- average_cuisine[1:10,]
ggplot(worst10, aes(reorder(x = CUISINE.DESCRIPTION, --average_score), average_score, fill = CUISINE.DESCRIPTION)) + geom_bar(stat='identity') + coord_flip() + theme(legend.position = 'none')+ggtitle("Average score of Worst 10 cuisines")+xlab("Cuisine description")+ylab("average score")+geom_text(aes(label = sprintf("%.2f", average_score)),position=position_stack(vjust=0.5))

n <- nrow(average_cuisine)
best10 <- average_cuisine[(n- 10):n,]
best10 <- best10[order(best10$average_score),]
ggplot(best10, aes(reorder(x = CUISINE.DESCRIPTION, -average_score), average_score, fill = CUISINE.DESCRIPTION)) + geom_bar(stat='identity') + coord_flip() + theme(legend.position = 'none')+ggtitle("Average score of top 10 cuisines")+xlab("Cuisine description")+ylab("average score")+geom_text(aes(label = sprintf("%.2f", average_score)),position = position_dodge(width = 1),#position=position_stack(vjust=0.5)
vjust = 0.5, size = 4)

It is interesting that the mysterious “not applicable”" cuisine is one of the best!
In this next plot, we wanted to see if the average score significantly differed by Borough
average_borough <- average_scores %>% group_by(BORO) %>% na.omit %>%
summarize(average_score = mean(SCORE))
ggplot(average_borough, aes(reorder(x = BORO, --average_score), average_score, fill = BORO)) + geom_bar(stat='identity') + theme(legend.position = 'none')+ggtitle("Average score across boroughs")+xlab("Borough")+ylab("average score")+geom_text(aes(label = sprintf("%.2f", average_score)),position = position_dodge(width = 1),
vjust = -0.5, size = 3)

Although we see slight difference, the boroughs have approximately the same average score. Staten Island may be the one exception. We also faceted by year to see if that made a difference, but the results were essentially the same as in the plot above.
So far we looked at grades and scores but not the actual violations. Whare are the top violations restaurants usually face?
violations<- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET, -ZIPCODE,
-PHONE, -INSPECTION.DATE, -ACTION,
-VIOLATION.CODE,
-CRITICAL.FLAG, -GRADE, -GRADE.DATE,
-RECORD.DATE, -INSPECTION.TYPE)
vs <- violations %>% group_by(VIOLATION.DESCRIPTION) %>% na.omit %>%
summarize(count = n())
vs <- arrange(vs, -count)
topviolations <- vs[1:10,]
library(stringr)
topviolations$viol = str_wrap(topviolations$VIOLATION.DESCRIPTION, width = 15)
ggplot(topviolations, aes(reorder(viol, -count), count,fill=viol)) + geom_bar(stat='identity') +
theme(legend.position = 'none')+ggtitle("Top 10 violations")+xlab("Violation description")+ylab("count")+geom_text(aes(label = sprintf("%.0f", count)),
position = position_dodge(width = 1),
vjust = -0.5, size = 7)

We also hypothesized that the type of inspections would generally vary by Borough but even this was mostly consistent.
library(viridis)
mos<- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET, -ZIPCODE,
-PHONE, -ACTION,
-VIOLATION.CODE,
-CRITICAL.FLAG, -GRADE, -GRADE.DATE,
-RECORD.DATE, -SCORE, -CUISINE.DESCRIPTION, -VIOLATION.DESCRIPTION)
mos$year <- factor(as.numeric( format(mos$INSPECTION.DATE , '%Y')))
mos <- mos %>% select(-INSPECTION.DATE)
average_mos <- mos %>% group_by(BORO, year, INSPECTION.TYPE) %>% tally %>%
group_by(BORO, year) %>%
mutate(p = n / sum(n))
#average_cuisine <- arrange(average_cuisine, -average_score)
library(vcd)
average_mos <- average_mos %>% select(-n)
ggplot(average_mos, aes(BORO,
INSPECTION.TYPE, fill = p)) +
geom_tile() +
scale_fill_viridis() +
#facet_wrap(~BORO)
ggtitle("AVERAGE VIOLATION SCORE BY ZIP CODE\n ")+
theme(axis.text.x=element_text(angle=-45, hjust=.1),
plot.title=element_text(margin=margin(b=.5), size = 15))+guides(fill=guide_legend(title="percentage"))

One thing we noticed was that Staten island has the most Cycle Inspection/Initial Inspection. Maybe they were opening up many new restuarants.
One factor of our data set we haven’t discussed too much is the Critical flag, saying whether or not a violation is critical. Once again, we assumed that over the years and across different boroughs, there would be some pattern in critical violations. As can be inferred from the following plot, there is not.
CriticalityData<- ViolationsData %>% select(BORO,INSPECTION.DATE,CRITICAL.FLAG) %>% na.omit()
CriticalityData$year<-factor(as.numeric( format(CriticalityData$INSPECTION.DATE , '%Y')))
#CriticalityData <- CriticalityData %>%select(-INSPECTION.DATE)
CriticalityData <- CriticalityData %>%select(-INSPECTION.DATE) %>%gather(key, value, -BORO, -year) %>% group_by(BORO, year,key,value) %>%tally %>% spread(value, n, fill = 0)
names(CriticalityData)[5] <- "NotApplicable"
names(CriticalityData)[6] <- "NonCritical"
CriticalityDataPercentage<-CriticalityData %>% summarize(criticalPercent = Critical/(Critical+NotApplicable+NonCritical), NotApplicablePercent = NotApplicable/(Critical+NotApplicable+NonCritical), NonCriticalPercent = NonCritical/(Critical+NotApplicable+NonCritical))#
names(CriticalityDataPercentage)[4] <- "Critical"
names(CriticalityDataPercentage)[5] <- "NotApplicable"
names(CriticalityDataPercentage)[6] <- "NonCritical"
CriticalityDataPercentage<-CriticalityDataPercentage%>% gather(key1, value, -BORO, -year,-key)
ggplot(CriticalityDataPercentage, aes(BORO, value, fill = key1)) +
geom_bar(stat="identity", position = "dodge") +
scale_fill_brewer(palette = "Set1")+ xlab("BOROUGH")+ylab("CRITICALITY PERCENTAGES") +theme(axis.text.x = element_text(angle = 45, hjust = 1))+ ggtitle("Grouped barchart of grade frequency in each cuisine category \n when there was a violation reported")+facet_wrap(~year,nrow=2,ncol=3)+guides(fill=guide_legend(title="Criticality \n category"))

We attempted to further analyze the critical flag but we learned that the critical flag did not have too much impact on grade or scores. There was a lot of data with a grade of A but a Critical flag while others with a very high score by no critical flag.
For the remainder of the analysis, we will be working with Tableau. We chose Tableau because we wanted to plot elegent maps. Tableau provides a simpler and more elegent way to do so than in R.
The code chunks will generate the data that we upload to Tableau. In the following analysis, we explore the proportion of A grades based on neighborhood over the years.
#####GENERATE GRADE PROPOERTION DATASET BY YEAR FOR TABLEAU PLOTTING
zipdata<- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET,
-PHONE, -ACTION,
-VIOLATION.CODE,
-CRITICAL.FLAG, -SCORE, -GRADE.DATE,
-RECORD.DATE, -INSPECTION.TYPE, -VIOLATION.DESCRIPTION, -CUISINE.DESCRIPTION, -BORO) %>% na.omit()
zipdata$year<-factor(as.numeric( format(zipdata$INSPECTION.DATE , '%Y')))
zipdataGradePercentage <- zipdata %>%select(-INSPECTION.DATE) %>%gather(key, value, -ZIPCODE, -year) %>% group_by(ZIPCODE, year, key, value) %>%
tally %>% spread(value, n, fill = 0) %>% summarize(aprop = A/(A+B+C), bprop = B/(A+B+C), cprop = C/(A+B+C) )
# ggplot(zipdataGradePercentage, aes(reorder(x = ZIPCODE, --aprop), aprop)) + geom_bar(stat='identity') +
# coord_flip() + facet_wrap(~year)
# theme( axis.text = element_text(size = 3))
knitr::include_graphics('Aprop1.png')

knitr::include_graphics('Aprop2.png')

knitr::include_graphics('Aprop3.png')

knitr::include_graphics('Aprop4.png')

knitr::include_graphics('Aprop5.png')

Over the years, the proportion of A’s has increased, as represented by the darker red shading of the map. It is too early to study 2017 in depth due to the limited number of inspections so far.
Let’s look at how the proportion of B’s change.
knitr::include_graphics('Bprop1.png')

knitr::include_graphics('Bprop2.png')

knitr::include_graphics('Bprop3.png')

knitr::include_graphics('Bprop4.png')

knitr::include_graphics('Bprop5.png')

We can see that over the years, there seem to be less B’s which makes sense since over the years we have more grades of A.
Let’s look at the average scores by neighborhood. We have already done so by cuisine.
knitr::include_graphics('AvgViolScoreByZip2013.png')

knitr::include_graphics('AvgViolScoreByZip2014.png')

knitr::include_graphics('AvgViolScoreByZip2015.png')

knitr::include_graphics('AvgViolScoreByZip2016.png')

knitr::include_graphics('AvgViolScoreByZip2017.png')

Over the years, we have a lower Average Score. These NYC inspections must be prompting resturants to improve their facilities and follow regulations!
We decided to see which areas had the highest average number of reinspections. Maybe this can explain the better scores and grades over time.
### DATA GENERATION
library(stringr)
reinspect <- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET, -CUISINE.DESCRIPTION, -BORO, -SCORE,
-PHONE, INSPECTION.DATE, -ACTION,
-VIOLATION.CODE,
-CRITICAL.FLAG, -GRADE, -GRADE.DATE,
-RECORD.DATE)
reinspect$year<-factor(as.numeric( format(reinspect$INSPECTION.DATE , '%Y')))
#inspection_types <- INSPECTION.TYPE
reinspect <- reinspect %>%select(-INSPECTION.DATE) %>% na.omit %>% filter(str_detect(INSPECTION.TYPE, "Re-inspection"))%>%group_by(VIOLATION.DESCRIPTION, year, ZIPCODE ) %>% tally# summarise(re = sum(str_count(reinspect$INSPECTION.TYPE, "Re-inspection")))
knitr::include_graphics('AvgReinspect2013.png')

knitr::include_graphics('AvgReinspect2014.png')

knitr::include_graphics('AvgReinspect2015.png')

knitr::include_graphics('AvgReinspect2016.png')

knitr::include_graphics('AvgReinspect2017.png')

Interestingly enough, the areas with the most reinspections seem to be the ones in which the grades and scores improved. The system of reinspections must be working!
As a last bit of analysis, we decided to help settle a huge dilemna : Where should you get your coffee, Starbucks or Dunking Donuts?
##DATA GENERATION CODE
library(stringr)
ChainssDf<-ViolationsData%>% mutate(isStarbucks=str_detect(DBA,"STARBUCK")) %>% mutate(isDunkin=str_detect(DBA,"DUNKIN"))
ChainssDf$DBA[ChainssDf$isStarbucks==TRUE]<-"STARBUCKS"
ChainssDf$DBA[ChainssDf$isDunkin==TRUE]<-"DUNKIN"
ChainssDf<-ChainssDf%>%filter(DBA %in% c("STARBUCKS","DUNKIN"))
ChainssDf<-ChainssDf%>%select(DBA,BORO,INSPECTION.DATE,ZIPCODE,SCORE,VIOLATION.DESCRIPTION,GRADE)
ChainssDf$year<-factor(as.numeric( format(ChainssDf$INSPECTION.DATE , '%Y')))
ChainssDf<-ChainssDf%>%select(-INSPECTION.DATE)
As you can see, Dunking Donuts has more critical violations than Starbucks in every Borough. Noticible differences are especially see in Brooklyn and Manhattan.
knitr::include_graphics('DS1.png')

Both establishments shared the same top violations. Let’s see what percentage of these violations each has.
knitr::include_graphics('DS2.png')

Once again, Starbucks is the winner!
What about the average score?
knitr::include_graphics('DS3.png')

Regardles of the year, the average score of Dunking Donuts has been higher. The higher the score, the worse. Noticible differences are seen in 2015 and the first three months of 2017.
Let’s see if the Borough your in should impact your choice.
knitr::include_graphics('DS4.png')

I guess when you’re in Brooklyn, it doesn’t matter but everywhere else, stick the Starbucks, especially you Staten Island folks!
LS0tCnRpdGxlOiAiVG8gRWF0IE9yIE5vdCBUbyBFYXQ/IgphdXRob3I6ICJKb25hdGhhbiBHYWxzdXJrYXIgLSBqZmcyMTUwIHwgTGFrc2h5YSBHYXJnIC0gbGcyOTA2IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCiMjIEludHJvZHVjdGlvbgoKSW4gb25lIG9mIHRoZSBncmVhdGVzdCBjaXRpZXMgaW4gdGhlIHdvcmxkLCBOWUMsIHdlIGhhdmUgYW4gYWJ1bmRhbnQgYW1vdW50IG9mIG9wdGlvbnMgdG8gY2hvb3NlIGZyb20gd2hlbiBpdCBjb21lcyB0byB3aGVyZSB3ZSBlYXQsIHdoZXRoZXIgd2UgYXJlIGxvb2tpbmcgZm9yIGZpbmUgZGluaW5nLCBmYXN0IGZvb2QsIG9yIHNvbWV0aGluZyBpbiBiZXR3ZWVuLiBUaGUgY3Vpc2luZSBjaG9pY2VzIHNlZW0ganVzdCBhcyBlbmRsZXNzLiBJcyB0aGVyZSBhIGdvb2Qgd2F5IHRvIGhlbHAgY2hvb3NlIGEgcmVzdGF1cmFudCB0byBlYXQgaW4gb3IgYSBnZW5lcmFsIGxvY2F0aW9uPyBBbHRob3VnaCBub3QgYW4gZWFzeSB0YXNrLCBvbmUgdGhpbmcgd2UgY2FuIGFsbCBhZ3JlZSBvbiBpcyB0aGF0IG5vYm9keSB3YW50cyB0byBlYXQgaW4gYSByZXN0YXVyYW50IHJpZGRlbiB3aXRoIGhlYWx0aCB2aW9sYXRpb25zLiBJbiBvdXIgcHJvamVjdCwgd2Ugd2lsbCBleHBsb3JlIGFuZCBhbmFseXplIE5ZQ+KAmXMgcmVzdGF1cmFudCBpbnNwZWN0aW9uIHJlc3VsdHMgZnJvbSAyMDEzLTIwMTcgb2YgdGhlIGZpdmUgYm9yb3VnaHMuCgpXZSBhcmUgaW50ZXJlc3RlZCBpbiBhbnN3ZXJpbmc6CgoxLiBXaGljaCBjdWlzaW5lcyBoYXZlIHRoZSBsZWFzdCBhbmQgbW9zdCB2aW9sYXRpb25zIGFsb25nIHdpdGggdGhlaXIgYXNzb2NpYXRlZCBzY29yZS4KCjIuIFdoYXQgcGFydHMgb2YgTllDIGhhdmUgdGhlIGxlYXN0IGFuZCBtb3N0IHZpb2xhdGlvbnM/CgozLiBXZSBoeXBvdGhlc2l6ZSB0aGF0IGxvY2F0aW9uIGlzIGhpZ2hseSBhc3NvY2lhdGVkIHdpdGggaW5zcGVjdGlvbiBncmFkZSBhbmQgc28gd2Ugd2lsbCBiZSBzZWFyY2hpbmcgZm9yIHBhdHRlcm5zIGJldHdlZW4gdGhlc2UgdmFyaWFibGVzLgoKNC4gV2UgYXJlIGFsc28gaW50ZXJlc3RlZCBpbiBzZWVpbmcgaG93IGluc3BlY3Rpb24gZ3JhZGUgYW5kIHNjb3JlIGNoYW5nZXMgb3ZlciB0aW1lICh5ZWFycykgYmFzZWQgdXBvbiBjdWlzaW5lIGFuZCBsb2NhdGlvbi4KCjUuIEEgZGVzY3JpcHRpb24gb2YgdmlvbGF0aW9ucyBpcyBhbHNvIHByb3ZpZGVkIGluIHRoZSBkYXRhIGFuZCB3ZSB3b3VsZCBsaWtlIHRvIGJldHRlciB1bmRlcnN0YW5kIHRoZSBjb21tb24gY2F1c2VzIG9mIHRob3NlIHZpb2xhdGlvbnMgYmFzZWQgdXBvbiB0aGUgZGVzY3JpcHRpb24uCgo2LiBJcyB0aGVyZSBhIHBhdHRlcm4vdHJlbmQgaW4gdmlvbGF0aW9ucy9pbnNwZWN0aW9uIHNjb3JlL2dyYWRlIGJhc2VkIHVwb24gcmVzdGF1cmFudCBjaGFpbnM/CgpXZSBmb3VuZCB0aGlzIGRhdGEgc2V0IGJ5IGV4cGxvcmluZyBOWUMgb3BlbiBkYXRhIHNldHMuIE91ciBsb3ZlIGZvciBmb29kIGFuZCBoZWFsdGggbWFkZSB0aGlzIGEgZ3JlYXQgb3B0aW9uLiBPbmUgb2Ygb3VyIHRlYW0gbWVtYmVycyB3aG8gcmVjZW50bHkgbW92ZWQgdG8gTllDIGlzIGhpZ2hseSBzZWxlY3RpdmUgYWJvdXQgdGhlIGZvb2Qgc2hlIGVhdHMgZHVlIHRvIGhlciByYXJlIGhlYWx0aCBjb25kaXRpb24gYW5kIGhlbmNlLCBoYXZpbmcgdGhlIGtpbmRzIG9mIHF1ZXN0aW9ucyBtZW50aW9uZWQgYWJvdmUgYW5zd2VyZWQgY2FuIHByb3ZlIHRvIGJlIGEgZ3JlYXQgYXNzZXQgdG8gYm90aCBoZXIgYW5kIG90aGVycyBzdWZmZXJpbmcgZnJvbSBoZWFsdGggY29uZGl0aW9ucyBvciB3aG8gbWF5IGp1c3QgYmUgcGlja3kgZWF0ZXJzISBUaGUgZGF0YSBjYW4gYmUgZm91bmQgYW5kIGRvd25sb2FkZWQgaGVyZTogaHR0cHM6Ly9kYXRhLmNpdHlvZm5ld3lvcmsudXMvSGVhbHRoL0RPSE1ILU5ldy1Zb3JrLUNpdHktUmVzdGF1cmFudC1JbnNwZWN0aW9uLVJlc3VsdHMveHg2Ny1rdDU5CgpUbyBkb3dubG9hZCwgY2xpY2sgdGhlIGV4cG9ydCBidXR0b24gb24gdGhlIHJpZ2h0IC0+IERvd25sb2FkIGFzIC0+IGNob29zZSB5b3VyIGZvcm1hdC4gRm9yIHRoaXMgYXNzaWduZW1lbnQgd2UgdXNlZCB0aGUgQ1NWIGZvcm1hdC4KCiMjIFRlYW0KCiMjIyMjIFRlYW0gTWVtYmVyczoKKyBKb25hdGhhbiBHYWxzdXJrYXIKKyBMYWtzaHlhIEdhcmcKCiMjIyMjIFRhc2sgRGlzdHJpYnV0aW9uCkdldCB0YWJsZSBmb3JtYXQgZm9yIHRoaXMKCiMjIEFuYWx5c2lzIG9mIERhdGEgUXVhbGl0eQpUbyBiZWdpbiBvdXIgYW5hbHlzaXMgb2YgZGF0YSBxdWFsaXR5LCBsZXQncyBsb2FkIG91ciBkYXRhLgpgYGB7cn0KVmlvbGF0aW9uc0RhdGEgPC0gcmVhZC5jc3YoZmlsZT0iaW5zcGVjdGlvbi5jc3YiLCBoZWFkZXI9VFJVRSwgc2VwPSIsIiwgYXMuaXM9VFJVRSkKYGBgCgpJbiBvcmRlciB0byBtb3JlIGVhc2lseSB3b3JrIHdpdGggb3VyIGRhdGEgbGV0J3MgZW5zdXJlIHRoYXQgZXZlcnkgZGF0ZSBpcyBpbiBhIGRhdGUgZm9ybWF0IHJhdGhlciB0aGFuIGEgc3RyaW5nIGFuZCBldmVyeSBzdHJpbmcgaXMgYSBmYWN0b3IgdmFyaWFibGUuCmBgYHtyIG1lc3NhZ2U9RkFMU0V9CgpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQojI0RhdGUgY29udmVyc2lvbgpWaW9sYXRpb25zRGF0YSA8LSBWaW9sYXRpb25zRGF0YSAlPiUKICBtdXRhdGUoSU5TUEVDVElPTi5EQVRFPSBhcy5EYXRlKElOU1BFQ1RJT04uREFURSwgZm9ybWF0PSAiJW0vJWQvJVkiKSklPiUKICBtdXRhdGUoR1JBREUuREFURT0gYXMuRGF0ZShHUkFERS5EQVRFLCBmb3JtYXQ9ICIlbS8lZC8lWSIpKSU+JQogIG11dGF0ZShSRUNPUkQuREFURT0gYXMuRGF0ZShSRUNPUkQuREFURSwgZm9ybWF0PSAiJW0vJWQvJVkiKSkKIyNGYWN0b3IgY29udmVyc2lvbgpWaW9sYXRpb25zRGF0YSA8LSBWaW9sYXRpb25zRGF0YSAlPiUKICBtdXRhdGUoQ1VJU0lORS5ERVNDUklQVElPTj0gYXMuZmFjdG9yKENVSVNJTkUuREVTQ1JJUFRJT04pKSU+JQogIG11dGF0ZShCT1JPPSBhcy5mYWN0b3IoQk9STykpJT4lCiAgbXV0YXRlKFZJT0xBVElPTi5DT0RFPSBhcy5mYWN0b3IoVklPTEFUSU9OLkNPREUpKSU+JQogIG11dGF0ZShDUklUSUNBTC5GTEFHPSBhcy5mYWN0b3IoQ1JJVElDQUwuRkxBRykpJT4lCiAgbXV0YXRlKEdSQURFPSBhcy5mYWN0b3IoR1JBREUpKSU+JQogIG11dGF0ZShJTlNQRUNUSU9OLlRZUEU9IGFzLmZhY3RvcihJTlNQRUNUSU9OLlRZUEUpKQpgYGAKCgpNYW55IG9mIHRoZSBxdWVzdGlvbnMgd2UgYXJlIGludGVyZXN0ZWQgaW4gYW5zd2VyaW5nIGludm9sdmUgdHJlbmRzIGFjcm9zcyByZXN0dWFyYW50IGxvY2F0aW9ucy4gV2UgZmlyc3QgY2hlY2tlZCB0byBzZWUgdGhlIG51bWJlciBvZiByZXN0dWFyYW50IGluc3BlY3Rpb25zIGJ5IGJvcm91Z2guIEZyb20gdGhlIHBsb3QgYmVsb3csIHdlIG5vdGljZWQgdGhhdCB0aGVyZSB3ZXJlIGEgbnVtYmVyIG9mIGluc3BlY3Rpb25zIGluIHdoaWNoIHRoZSBCb3JvdWdoIGluZm9ybWF0aW9uIHdhcyBtaXNzaW5nIGFuZCB3b24ndCBoZWxwIG91ciBhbmFseXNpcy4KYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKYm9yb3VnaFBsb3QgPC0gZ2dwbG90KFZpb2xhdGlvbnNEYXRhLCBhZXMoQk9STywgZmlsbD1CT1JPKSkKYm9yb3VnaFBsb3QgKyBnZW9tX2JhcigpKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgZ2d0aXRsZSgnSW5zcGVjdGlvbiBDb3VudCBieSBCb3JvdWdoJykgKyAKICBsYWJzKHggPSAiQm9yb3VnaCIsIHkgPSJOdW1iZXIgb2YgSW5zcGVjdGlvbnMiKQpgYGAKCkFub3RoZXIgbWFpbiBmZWF0dXJlIG9mIG91ciBkYXRhIHNldCBpcyB0aGUgaW5zcGVjdGlvbiB5ZWFyIHNpbmNlIHdlIHdpc2ggdG8gZXhwbG9yZSBwYXR0ZXJzIGluIGluc3BlY3Rpb24gZ3JhZGVzL3Njb3JlcyBvdmVyIHRoZSB5ZWFycy4gRnJvbSB0aGUgcGxvdCBiZWxvdywgd2Ugbm90aWNlZCB0aGF0IHRoZXJlIGlzIGFsbW9zdCBubyBpbnNwZWN0aW9uIGRhdGEgYmVmb3JlIDIwMTMgYW5kIHN1cnByaXNpbmdseSBtb3JlIGluc3BlY3Rpb24gZGF0YSBpbiAxOTAwIHRoYW4gMjAxMiBhbmQgMjAxMS4gV2UgZGVjaWRlZCB0byBvbmx5IHdvcmsgd2l0aCBkYXRhIGZyb20gMjAxMyBhbmQgdXAuIEl0IGlzIGltcG9ydGFudCB0byBub3RlIHRoYXQgdGhlIG51bWJlciBvZiBpbnNwZWN0aW9ucyBmb3IgMjAxNyBpcyBsb3cgc2luY2UgdGhlIDIwMTcgZGF0YSBpcyBvbmx5IGF2YWlsYWJsZSBmcm9tIEphbnVhcnkgLSBNYXJjaC4KYGBge3J9CnZpb2xhdGlvblllYXJzUGxvdCA8LSBnZ3Bsb3QoVmlvbGF0aW9uc0RhdGEsIGFlcyhmYWN0b3IoYXMubnVtZXJpYyhmb3JtYXQoSU5TUEVDVElPTi5EQVRFLCAnJVknKSkpLCBmaWxsPSJSZWQiKSkKdmlvbGF0aW9uWWVhcnNQbG90ICsgZ2VvbV9iYXIoKStjb29yZF9mbGlwKCkrIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICt4bGFiKCJJbnNwZWN0aW9uIFllYXIiKSt5bGFiKCJJbnNwZWN0aW9uIENvdW50cyIpICsgZ2d0aXRsZSgiSW5zcGVjdGlvbiBDb3VudCBieSBZZWFyIikKYGBgCgpBbm90aGVyIGNydWNpYWwgZmVhdHVyZSBvZiBvdXIgZGF0YSBzZXQgaXMgZ3JhZGUgYSByZXN0YXVyYW50IHJlY2VpdmVkIGFmdGVyIGluc3BlY3Rpb24uIFdlIGRlY2lkZWQgdG8gcGxvdCBhIHN0YWNrZWQgYmFyIGNoYXJ0IGZvciB0byBzZWUgdGhlIGNvdW50IG9mIGVhY2ggdHlwZSBvZiBncmFkZSBmb3IgZXZlcnkgY3Vpc2luZS4gV2UgdXNlZCBhIHN0YWNrZWQgYmFyIGNoYXJ0IGJlY2F1c2Ugd2Ugd2FudGVkIHRvIHF1aWNrbHkgYXNzZXNzIHRoZSBtYWduaXR1ZGUgbWlzc2luZyB3aXRob3V0IHRha2luZyB1cCBleHRyYSByb29tLiBGcm9tIHRoZSBwbG90IGJlbG93LCBpdCB3YXMgc2hvY2tpbmcgdG8gc2VlIHRoYXQgd2UgZ2VuZXJhbGx5IGhhZCBtb3JlIG1pc3NpbmcgZ3JhZGVzIHRoYW4gZ3JhZGVzLiBUaGlzIHdhcyB0cnVlIHJlZ2FyZGxzcyBvZiBjdWlzaW5lLiBJdCB3YXMgYWxzbyBpbnRlcmVzdGVkIHRoYXQgdGhlIGdyYWRlcyB3ZXJlIHB1cmVseSBtaXNzaW5nIGFuZCBub3QgY2F0ZWdvcml6ZWQgYXMgIk5vdCBZZXQgR3JhZGVkIi4KYGBge3IsZmlnLmhlaWdodD0xMn0KZ2dwbG90KFZpb2xhdGlvbnNEYXRhLCBhZXMoQ1VJU0lORS5ERVNDUklQVElPTiwgZmlsbCA9IEdSQURFKSkgKyBnZW9tX2JhcigpICsgCiAgY29vcmRfZmxpcCgpK2dndGl0bGUoInN0YWNrZWQgYmFyIGNoYXJ0IG9mIGdyYWRlIGRpc3RyaWJ1dGlvbnMgYWNyb3NzIGN1aXNpbmVzIikKYGBgCgpUbyBzdGF5IG9uIHRoZSB0b3BpYyBvZiBncmFkZXMsIGFmdGVyIHJlc2VhcmNoaW5nIHRoZSBsZXR0ZXIgZ3JhZGluZyBwcm9ncmFtLCB3ZSBmb3VuZCB0aGUgZm9sbG93aW5nIGluZm9ybWF0aW9uOiAKKyBBIHNjb3JlIG9mIGxlc3MgdGhhbiAxNCBwb2ludHMgb24gZWl0aGVyIGluaXRpYWwgb3IgcmUtaW5zcGVjdGlvbiByZXN1bHRzIGluIGFuIOKAnEHigJ0gZ3JhZGUKKyBPbiByZS1pbnNwZWN0aW9uLCBhIHNjb3JlIG9mIDE0LTI3IHBvaW50cyBtZWFucyBhIHJlc3RhdXJhbnQgcmVjZWl2ZXMgYm90aCBhIOKAnELigJ0gZ3JhZGUgYW5kIGEg4oCcR3JhZGUgUGVuZGluZ+KAnSBjYXJkLgorIE9uIHJlLWluc3BlY3Rpb24sIGEgc2NvcmUgb2YgMjggb3IgbW9yZSBwb2ludHMgbWVhbnMgYSByZXN0YXVyYW50IHJlY2VpdmVzIGJvdGggYSDigJxD4oCdIGdyYWRlIGFuZCBhIOKAnEdyYWRlIFBlbmRpbmfigJ0gY2FyZC4KCkJvdGggWiBhbmQgUCByZXByZXNlbnQgZ3JhZGUgcGVuZGluZywgaG93ZXZlciBQIHJlcHJlc2VudHMgYSBHcmFkZSBQZW5kaW5nIGlzc3VlZCBvbiByZS1vcGVuaW5nIGZvbGxvd2luZyBhbiBpbml0aWFsIGluc3BlY3Rpb24gdGhhdCByZXN1bHRlZCBpbiBhIGNsb3N1cmUuCgpXZSBhbHNvIGRpc2NvdmVyZWQgdGhhdCBub3QgZXZlcnkgaW5zcGVjdGlvbiBpcyAiZ3JhZGFibGUiLiBHcmFkYWJsZSBpbnNwZWN0aW9ucyBoYXZlIHRoZSBmb2xsb3dpbmcgcHJvcGVydGllczoKCisgSU5TUEVDVElPTiBUWVBFIGluIChDeWNsZSBJbnNwZWN0aW9uL0luaXRpYWwgSW5zcGVjdGlvbiwgQ3ljbGUgSW5zcGVjdGlvbi9SZS1JbnNwZWN0aW9uLCBQcmUtUGVybWl0IChPcGVyYXRpb25hbCkvSW5pdGlhbCBJbnNwZWN0aW9uLCBQcmUtUGVybWl0IChPcGVyYXRpb25hbCkvUmUtSW5zcGVjdGlvbikKKyBBQ1RJT04gaW4gKFZpb2xhdGlvbnMgd2VyZSBjaXRlZCBpbiB0aGUgZm9sbG93aW5nIGFyZWEocyksIE5vIHZpb2xhdGlvbnMgd2VyZSByZWNvcmRlZCBhdCB0aGUgdGltZSBvZiB0aGlzIGluc3BlY3Rpb24sIEVzdGFibGlzaG1lbnQgQ2xvc2VkIGJ5IERPSE1IKQorIElOU1BFQ1RJT04gREFURSA+IEp1bHkgMjYsIDIwMTAKClRoaXMgY2FuIHByb2JhYmx5IGV4cGxhaW4gYSBmYWlyIGFtb3VudCBvZiB0aGUgbWlzc2luZyBncmFkZSBkYXRhIG9ic2VydmVkIGluIG91ciBwbG90LgoKQWNjb3JkaW5nIHRvIHRoZSBBQk9VVCB0aGUgZGF0YSBzZXQgcGFnZTogVGhlIFNDT1JFIGFuZCBHUkFERSBmaWVsZHMgbWF5IGJlIGluY29uc2lzdGVudCB3aXRoIGVhY2ggb3RoZXIgYmVjYXVzZSBvZiBsaW1pdGF0aW9ucyBvciBlcnJvcnMgaW4gdGhlIGRhdGEgc3lzdGVtcy4gVGhhdCBpcyB0byBzYXksIHNjb3JlcyBvZiAwLTEzLCAxNC0yNyBhbmQgMjgrIGFyZSBub3QgYWx3YXlzIGFjY29tcGFuaWVkIGJ5IEEsIEIgYW5kIEMgZ3JhZGVzLCByZXNwZWN0aXZlbHksIHdoZW4gdGhleSBzaG91bGQgYmUuIFRoZXJlIG1heSBhbHNvIGJlIGNhc2VzIHdoZXJlIGEgZ3JhZGUgY2FyZCB3YXMgZ2l2ZW4gb3V0IGJ1dCBhIHJlY29yZCBvZiB0aGF0IGdyYWRlIGlzc3VhbmNlIGlzIG1pc3NpbmcgZnJvbSB0aGUgZGF0YSBzeXN0ZW0sIGFuZCB0aGVyZWZvcmUgbWlzc2luZyBmcm9tIHRoaXMgZGF0YXNldCwgZXZlbiB0aG91Z2ggdGhlIFNDT1JFIGZpZWxkIGlzIHBvcHVsYXRlZC4gIE5vdGUgdGhhdCB3aGVuIGluaXRpYWwgaW5zcGVjdGlvbnMgYXJlIGFkanVkaWNhdGVkIGRvd24gdG8gdGhlIEEgcmFuZ2UsIHRoZSBhYnNlbmNlIG9mIGFuIGFjY29tcGFueWluZyBncmFkZSBhc3NvY2lhdGVkIHdpdGggdGhhdCBpbnNwZWN0aW9uIGlzIGNvcnJlY3QsIGJlY2F1c2UgdGhlIGdyYWRlIHdvdWxkIG5vdCBiZSBhc3NpZ25lZCB1bnRpbCB0aGUgcmUtaW5zcGVjdGlvbiBpcyBwZXJmb3JtZWQuIAoKVG8gZ2FpbiBzb21lIGZpbmFsIGluc2lnaHQgb24gdGhlIGRhdGEgcXVhbGl0eSwgd2UgZGVjaWRlZCB0byBwbG90IHRoZSByZWxhdGlvbnNocCBiZXR3ZWVuIHRoZSBudW1iZXIgb2YgbWlzc2luZyBzY29yZXMgYnkgZ3JhZGUgYW5kIGJ5IHdoZXRoZXIgb3Igbm90IGEgdmlvbGF0aW9uIHdhcyByZXBvcnRlZC4gV2UgdHJhbnNmb3JtZWQgdGhlIGFjdGlvbnMgdGFrZW4gaW50byB0aHJlZSBjYXRlZ29yaWVzOgoxLiBObyB2aW9sYXRpb25zIHdlcmUgcmVjb3JkZWQgYXQgdGhlIHRpbWUgb2YgdGhpcyBpbnNwZWN0aW9uIHRvIE5vIFZpb2xhdGlvbgoyLiBBbnkgYWN0aW9uIHJlcG9ydGVkIHRvIFZpb2xhdGlvbiByZXBvcnRlZAozLiBNaXNzaW5nIGFjdGlvbnMgdG8gTkEKV2UgdGhlbiBjb3VudGVkIGlmIHRoZSBzY29yZSB3YXMgcHJvdmlkZWQgb3Igbm90LgoKYGBge3IsZmlnLmhlaWdodD00fQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpzY29yZV9ncmFkZSA8LSBWaW9sYXRpb25zRGF0YVsgLWMoMTo5LCAxMToxMywgMTY6MTgpIF0Kc2NvcmVfZ3JhZGVbc2NvcmVfZ3JhZGUgPT0gJyddIDwtIE5BCnNjb3JlX2dyYWRlX2NvbWJvcyA8LSBzY29yZV9ncmFkZSAgJT4lIG11dGF0ZShtaXNzaW5nX3Njb3JlID0gaWZlbHNlKGlzLm5hKFNDT1JFKSwgInllcyIsICJubyIpKQpzY29yZV9ncmFkZV9taXNzaW5nIDwtIGNvdW50KHNjb3JlX2dyYWRlX2NvbWJvcywgYygnR1JBREUnLCAnbWlzc2luZ19zY29yZScsICdBQ1RJT04nKSkKc2NvcmVfZ3JhZGVfbWlzc2luZyA8LSBzY29yZV9ncmFkZV9taXNzaW5nICU+JSAKICBtdXRhdGUodmlvbGF0aW9uID0gaWZlbHNlKEFDVElPTiA9PSAnTm8gdmlvbGF0aW9ucyB3ZXJlIHJlY29yZGVkIGF0IHRoZSB0aW1lIG9mIHRoaXMgaW5zcGVjdGlvbi4nLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vIHZpb2xhdGlvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGlzLm5hKHNjb3JlX2dyYWRlX21pc3NpbmckQUNUSU9OKSwgTkEsICJWaW9sYXRpb24gUmVwb3J0ZWQiKSkpICU+JQogIHNlbGVjdCgtYyhBQ1RJT04pKQpnZ3Bsb3Qoc2NvcmVfZ3JhZGVfbWlzc2luZywgYWVzKHggPSBHUkFERSwgeSA9IGxvZyhmcmVxKSwgZmlsbCA9IG1pc3Npbmdfc2NvcmUpKSArIAogIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknLCBwb3NpdGlvbiA9ICdkb2RnZScpICsgZmFjZXRfd3JhcCh+dmlvbGF0aW9uKSArIAogIGdndGl0bGUoIkdyYWRlIGFuZCBtaXNzaW5nIHNjb3JlIGNvbWJpbmF0aW9ucyBieSB2aW9sYXRpb24gcmVwb3J0IikgKwogIGxhYnMoeCA9ICJHcmFkZSIsIHkgPSAiTG9nKEZyZXF1ZW5jeSkiKQpgYGAKSW50ZXJlc3RpbmcgaW5zaWdodHMgZnJvbSBwbG90IGFib3ZlIGFyZToKCjEuIEdyYWRlcyBvZiBOQSByZXBvcnRlZCBoaWdoIGZyZXF1ZW5jeSBvZiBzY29yZSBpbiBib3RoIE5vIHZpb2xhdGlvbiBhbmQgdmlvbGF0aW9uIHJlcG9ydGVkIGNhdGVnb3J5LgoKMi4gQXQgZmlyc3QsIGl0IGFwcGVhcnMgdGhhdCBoaWdoIHNjb3JlcyBhcmUgcmVsYXRlZCB0byBsb3cgZ3JhZGVzIG9yIG5lZWRzIGdyYWRpbmcgYnV0IHRoZW4gd2UgZmluZCByZXN0YXVyYW50cyB3aXRoIGEgZ3JhZGUgb2YgQSB0aGF0IGhhcyB0aGUgc2FtZSBzY29yZSBhcyBhIHJlc3RhdXJhbnQgd2l0aCBhIGdyYWRlIG9mIEMuCgozLiBBbm90aGVyIGluc2lnaHQgYnkganVzdCBsb29raW5nIGF0IHRoZSBkYXRhIGlzIHdlIHN1cnByaXNpbmdseSBzYXcgdGhhdCByZXN0YXVyYW50cyB3aXRoIGEgY3JpdGljYWwgZmxhZyBzdGlsbCByZWNlaXZlIGdyYWRlcyBvZiBBLlRoaXMgbmVlZHMgZnVydGhlciBhbmFseXNpcy4gU0hPVUxEIFdFIE1BS0UgQSBQTE9UIEZPUiBUSElTPz8/PwoKIyMgRXhlY3V0aXZlIFN1bW1hcnkKTllDIHB1dHMgYSBsb3Qgb2YgdGltZSBhbmQgbW9uZXkgaW50byBpbnNwZWN0aW5nIHJlc3R1YXJhbnRzLiBXaHkgd291bGQgdGhleSBnbyB0aHJvdWdoIGFsbCB0aGlzIHRyb3VibGU/IFRvIGVuc3VyZSBxdWFsaXR5IG1lYWxzIGFuZCBzYXRpc2ZhY3Rpb24gb2YgTllDIHJlc2lkZW50cyBvZiBjb3Vyc2UhIEl0IGlzIGltcG9ydGFudCBmb3IgcmVzdGF1cmFudHMgYW5kIGVzdGFibGlzaG1lbnQgdGhhdCBtZWV0IGF0IGxlYXN0IHRoZSBtaW5pbXVtIHJlcXVpcmVtZW50cyBvZiBoZWFsdGggYW5kIHNhZmV0eSByZWd1bGF0aW9ucyBpbiBvcmRlciB0byBwcm9tb3RlIGxlc3MgZm9vZCBzaWNrIHJlc2lkZW50cyBhbmQgYSBjbGVhbmVyIE5ZQy4gCgpIb3cgY2FuIHdlIHRlbGwgaWYgdGhlc2UgaW5zcGVjdGlvbnMgYXJlIGFjdHVhbGx5IHdvcmtpbmcgdG8gcHJvbW90ZSByZXN0dWFyYW50cyB0byBtZWV0IHJlZ3VsYXRpb25zPyBMZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgcHJvcG9ydGlvbiBvZiBzY29yZXMgdGhhdCB3ZXJlIGdyYWRlZCBhbiBBIGluIDIwMTMgYW5kIHRoZSBwcm9wb3J0aW9uIG9mIHNjb3JlcyB0aGF0IHdlcmUgZ3JhZGVkIGFuIEEgaW4gMjAxNi4gTGV0J3MgdmlldyB0aGlzIGluZm9ybWF0aW9uIGJ5IGxvY2F0aW9uIHNvIHRoYXQgeW91IGtub3cgd2hhdCBuZWlnaGJvcmhvb2QgdG8gY2hvb3NlIHdoZW4geW91J3JlIGNyYXZpbmcgYSByZXN0YXVyYW50LgoKYGBge3IgZWNobyA9IEZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXByb3A1LnBuZycpCmBgYAoKYGBge3IgZWNobyA9IEZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXByb3AyLnBuZycpCmBgYAoKVGhlIGRhcmtlciB0aGUgc2hhZGUgb2YgcmVkLCB0aGUgaGlnaGVyIHByb3BvcnRpb24gb2YgQSBncmFkZXMuIEl0IGlzIGNsZWFyIHRoYXQgb3ZlciB0aGUgbGFzdCAzIHllYXJzLCB0aGUgcHJvcG9ydGlvbiBvZiByZXN0dWFyYW50cyB3aXRoIGEgZ3JhZGUgb2YgYW4gQSBoYXMgaW5zY3JlYXNlZC4gTllDIGluc3BlY3Rpb25zIG11c3QgYmUgd29ya2luZyB0byBpbXByb3ZlIHRoZSBxdWFsaXR5IG9mIHRoZSByZXN0dWFyYW50cyB3ZSBlYXQgaW4hIEluIDIwMTMsIGl0IHNlZW1zIHRoYXQgdGhlIHRoZXJlIHdlcmUgb25seSBhIGZldyBuZWlnaGJvcmhvb2RzIHdpdGggYW4gZXh0cmVtZWx5IGhpZ2ggcHJvcG9ydGlvbiBvZiBBIGdyYWRlcy4gT25seSAzIGFyZWFzIGluIFN0YXRlbiBJc2xhbmQsIDEgaW4gTG9uZyBJc2xhbmQsIGEgZmV3IGluIEJyb29rbHluLCBNYW5oYXR0YW4sIGFuZCB0aGUgQnJvbnguIEluIDIwMTYgb24gdGhlIG90aGVyIGhhbmQsIHRoZSBwcm9wb3J0aW9uIG9mIEEgZ3JhZGVzIGlzIHZlcnkgaGlnaCBhbG1vc3QgcmVnYXJkbGVzIG9mIG5laWdoYm9yaG9vZC4gS2VlcCBpdCB1cCBOWUMgcmVzdGFydWFudCBpbnNwZWN0aW9ucyEKClRPIHNlZSB0aGlzIGZyb20gYW5vdGhlciBhbmdsZSwgbGV0J3MgbG9vayBhdCB0aGUgYXZlcmFnZSBzY29yZXMgcGVyIG5laWdoYm9yaG9vZCBpbiAyMDEzIGFuZCAyMDE2LiBUSEVZIFdFUkUgQklOTkVEIFRISVMgV0FZSkZESEpLSEZMU0RGRlNECgpgYGB7ciBlY2hvID0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBdmdWaW9sU2NvcmVCeVppcDIwMTMucG5nJykKYGBgCgpgYGB7ciBlY2hvID0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBdmdWaW9sU2NvcmVCeVppcDIwMTYucG5nJykKYGBgCgpKdXN0IGxvb2sgaG93IG11Y2ggbGlnaHRlciB0aGUgY29sb3Igb2YgZWFjaCBuZWlnaGJvcmhvb2QgZ290ISBMaWdodGVyIGNvbG9ycyBtZWFuIGEgbG93ZXIgYXZlcmFnZSBzY29yZSwgd2hpY2ggY29ycmVsYXRlcyB0byBsZXNzIHZpb2xhdGlvbnMgYW5kIGEgaGVhbHRoaWVyIGVzdGFibGlzaG1lbnQhCgpXZWxsIG5vdyB3ZSBrbm93IHdoYXQgbmVpZ2hib3Job29kcyB0byBiZSBpbiBmb3IgZXN0YWJsaXNobWVudHMgd2l0aCBsb3cgc2NvcmVzIGFuZCBBIGdyYWRlcywgYnV0IHdoYXQgYXJlIHRoZSBhdmVyYWdlIHNjb3JlcyBiYXNlZCB1cG9uIGN1aXNpbmU/CgpgYGB7ciBlY2hvID0gRkFMU0V9CmF2ZXJhZ2VfY3Vpc2luZSA8LSBWaW9sYXRpb25zRGF0YSAlPiUgIGdyb3VwX2J5KENVSVNJTkUuREVTQ1JJUFRJT04pICU+JSBuYS5vbWl0ICU+JQogIHN1bW1hcml6ZShhdmVyYWdlX3Njb3JlID0gbWVhbihTQ09SRSkpCmF2ZXJhZ2VfY3Vpc2luZSA8LSBhcnJhbmdlKGF2ZXJhZ2VfY3Vpc2luZSwgLWF2ZXJhZ2Vfc2NvcmUpCgphdmVyYWdlX2N1aXNpbmUgPC0gYXZlcmFnZV9zY29yZXMgJT4lICBncm91cF9ieShDVUlTSU5FLkRFU0NSSVBUSU9OKSAlPiUgbmEub21pdCAlPiUKICBzdW1tYXJpemUoYXZlcmFnZV9zY29yZSA9IG1lYW4oU0NPUkUpKQphdmVyYWdlX2N1aXNpbmUgPC0gYXJyYW5nZShhdmVyYWdlX2N1aXNpbmUsIC1hdmVyYWdlX3Njb3JlKQpgYGAKCmBgYHtyIGVjaG89RkFMU0V9Cm4gPC0gbnJvdyhhdmVyYWdlX2N1aXNpbmUpCmJlc3QxMCA8LSBhdmVyYWdlX2N1aXNpbmVbKG4tIDEwKTpuLF0KYmVzdDEwIDwtIGJlc3QxMFtvcmRlcihiZXN0MTAkYXZlcmFnZV9zY29yZSksXQoKZ2dwbG90KGJlc3QxMCwgYWVzKHJlb3JkZXIoeCA9IENVSVNJTkUuREVTQ1JJUFRJT04sIC1hdmVyYWdlX3Njb3JlKSwgYXZlcmFnZV9zY29yZSwgZmlsbCA9IENVSVNJTkUuREVTQ1JJUFRJT04pKSArIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JykgKyBjb29yZF9mbGlwKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScpK2dndGl0bGUoIkF2ZXJhZ2Ugc2NvcmUgb2YgdG9wIDEwIGN1aXNpbmVzIikreGxhYigiQ3Vpc2luZSBkZXNjcmlwdGlvbiIpK3lsYWIoImF2ZXJhZ2Ugc2NvcmUiKStnZW9tX3RleHQoYWVzKGxhYmVsID0gc3ByaW50ZigiJS4yZiIsIGF2ZXJhZ2Vfc2NvcmUpKSxwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksI3Bvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3QgPSAwLjUsIHNpemUgPSA0KQpgYGAKCmBgYHtyIGVjaG8gPSBGQUxTRX0Kd29yc3QxMCA8LSBhdmVyYWdlX2N1aXNpbmVbMToxMCxdCgpnZ3Bsb3Qod29yc3QxMCwgYWVzKHJlb3JkZXIoeCA9IENVSVNJTkUuREVTQ1JJUFRJT04sIC0tYXZlcmFnZV9zY29yZSksIGF2ZXJhZ2Vfc2NvcmUsIGZpbGwgPSBDVUlTSU5FLkRFU0NSSVBUSU9OKSkgKyBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpICsgY29vcmRfZmxpcCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnKStnZ3RpdGxlKCJBdmVyYWdlIHNjb3JlIG9mIFdvcnN0IDEwIGN1aXNpbmVzIikreGxhYigiQ3Vpc2luZSBkZXNjcmlwdGlvbiIpK3lsYWIoImF2ZXJhZ2Ugc2NvcmUiKStnZW9tX3RleHQoYWVzKGxhYmVsID0gc3ByaW50ZigiJS4yZiIsIGF2ZXJhZ2Vfc2NvcmUpKSxwb3NpdGlvbj1wb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpKQpgYGAKCkl0IGlzIGludGVyZXN0aW5nIHRoYXQgTm90IExpc3RlZC9Ob3QgQXBwbGljYWJsZSBhbmQgT3RoZXIgbWFkZSBpdCB0byB0aGUgdG9wIDEwIGJ1dCB0aGVyZSB5b3UgaGF2ZSBpdCwgdGhlIGJlc3QgYW5kIHdvcnN0IGN1aXNpbmVzIGJhc2VkIHVwb24gdGhlaXIgYXZlcmFnZSBzY29yZXMuCgojIyBNYWluIEFuYWx5c2lzCkFmdGVyIGFuYWx5emluZyB0aGUgcXVhbGl0eSBvZiB0aGUgZGF0YSBzZXQsIHdlIGdvdCByaWQgb2YgZGF0YSBpbiB3aGljaCB0aGUgQm9yb3VnaCBpcyBtaXNzaW5nIGFuZCB0aGUgeWVhciBpcyBiZWZvcmUgMjAxMy4KCmBgYHtyfQpWaW9sYXRpb25zRGF0YSA8LSBWaW9sYXRpb25zRGF0YSAlPiUgZmlsdGVyIChCT1JPICE9ICJNaXNzaW5nIikKVmlvbGF0aW9uc0RhdGEgPC0gVmlvbGF0aW9uc0RhdGEgJT4lIGZpbHRlcigKICBhcy5udW1lcmljKGZvcm1hdChJTlNQRUNUSU9OLkRBVEUgLCAnJVknKSkgPiAyMDEyKQpgYGAKCk5vdyB3ZSBjYW4gZ2V0IGEgYmV0dGVyIHBpY3R1cmUgb2YgdGhlIHRvdGFsIG51bWJlciBvZiBpbnNwZWN0aW9ucyBieSB5ZWFyIGFuZCBib3JvdWdoLgpgYGB7cn0KYm9yb3VnaFBsb3QgPC0gZ2dwbG90KFZpb2xhdGlvbnNEYXRhLCBhZXMoQk9STyxmaWxsPUJPUk8pKQpib3JvdWdoUGxvdCArIGdlb21fYmFyKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIAogIGZhY2V0X3dyYXAofmZhY3Rvcihhcy5udW1lcmljKCBmb3JtYXQoSU5TUEVDVElPTi5EQVRFICwgJyVZJykpKSkgKyAKICBnZ3RpdGxlKCJUb3RhbCBJbnNwZWN0aW9ucyBmcm9tIDIwMTMtMjAxNyBpbiBlYWNoIEJvcm91Z2giKSArCiAgeGxhYigiQm9yb3VnaCIpICsgeWxhYigiTnVtYmVyIG9mIEluc3BlY3Rpb25zIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCmBgYApBZnRlciAyMDEzLCB0aGVyZSBzZWVtcyB0byBiZSBhIGNvbnNpc3RlbnQgYW1vdW50IG9mIGluc3BlY3Rpb25zIGFjcm9zIHRoZSB5ZWFycy4gVGhlIG51bWJlciBvZiBpbnNwZWN0aW9ucyBieSBib3JvdWdoIGFsc28gc2VlbXMgdG8gbWFrZSBzZW5zZSBzaW5jZSB3ZSBleHBlY3QgTWFuaGF0dGFuIHRvIGhhdmUgdGhlIGxhcmdlc3QgbnVtYmVyIG9mIHJlc3R1YXJhbnRzLgoKTmV4dCwgd2UgdG9vayBhIGxvb2sgYXQgdGhlIGdyYWRlIGRpc3RyaWJ1dGlvbiBieSBib3JvdWdoLgpgYGB7cixmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTN9Cmluc3BlY3Rpb25fZ3JhZGVzIDwtIFZpb2xhdGlvbnNEYXRhICU+JSBzZWxlY3QoLUNBTUlTLCAtREJBLCAtQlVJTERJTkcsIC1TVFJFRVQsIC1aSVBDT0RFLCAtUEhPTkUsIC1BQ1RJT04sIC1WSU9MQVRJT04uQ09ERSwgLVZJT0xBVElPTi5ERVNDUklQVElPTiwgLUNSSVRJQ0FMLkZMQUcsIC1TQ09SRSwgLUdSQURFLkRBVEUsIC1SRUNPUkQuREFURSwgLUlOU1BFQ1RJT04uVFlQRSwtQ1VJU0lORS5ERVNDUklQVElPTikKCmluc3BlY3Rpb25fZ3JhZGVzX3dveWVhcjwtaW5zcGVjdGlvbl9ncmFkZXMgJT4lIHNlbGVjdCgtSU5TUEVDVElPTi5EQVRFKQoKaW5zcGVjdGlvbl9ncmFkZXNfd295ZWFyIDwtIGluc3BlY3Rpb25fZ3JhZGVzX3dveWVhciAlPiUgZ2F0aGVyKGtleSwgdmFsdWUsIC1CT1JPKSAlPiUgZ3JvdXBfYnkoQk9STywga2V5LCB2YWx1ZSkgJT4lIHRhbGx5ICU+JSBzcHJlYWQodmFsdWUsIG4sIGZpbGwgPSAwKSMgJT4lIGdhdGhlcihibGFoLCAtQk9STywgLWtleSkgI3N1bW1hcml6ZShhcHJvcCA9IEEvKEErQitDKykpCm5hbWVzKGluc3BlY3Rpb25fZ3JhZGVzX3dveWVhcilbbmFtZXMoaW5zcGVjdGlvbl9ncmFkZXNfd295ZWFyKT09ImtleSJdIDwtICJncmFkZSIKbmFtZXMoaW5zcGVjdGlvbl9ncmFkZXNfd295ZWFyKVtuYW1lcyhpbnNwZWN0aW9uX2dyYWRlc193b3llYXIpPT0iIl0gPC0gInVua25vd24iCmluc3BlY3Rpb25fZ3JhZGVzX3dveWVhciA8LSBpbnNwZWN0aW9uX2dyYWRlc193b3llYXIgJT4lIGdhdGhlcihrZXksIHZhbHVlLCAtQk9STywtZ3JhZGUpClJlbEZyZXE8LWZ1bmN0aW9uKG0pewogICAoKG0gKS9zdW0obSkpCiB9Cmluc3BlY3Rpb25fZ3JhZGVzX3dveWVhcjwtaW5zcGVjdGlvbl9ncmFkZXNfd295ZWFyICU+JSBncm91cF9ieShCT1JPLGdyYWRlKSAlPiUKICAgIG11dGF0ZShwZXJjZW50YWdlID0gKHZhbHVlL3N1bSh2YWx1ZSkpKjEwMCkKZ2dwbG90KGluc3BlY3Rpb25fZ3JhZGVzX3dveWVhciwgYWVzKEJPUk8sIHBlcmNlbnRhZ2UgLGZpbGw9IGtleSkpICsgCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBnZ3RpdGxlKCclR3JhZGUgZGlzdHJpYnV0aW9uIGFjcm9zcyBib3JvdWdocycpICsgCiAgbGFicyh4ID0gImJvcm91Z2hzIiwgeSA9InBlcmNlbnRhZ2UiKStndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IkdyYWRlIikpCgpgYGAKV2UgaW5pdGlhbGx5IGh5cG90aGVzaXplZCB0aGF0IHdlIHdvdWxkIHNlZSBhIHBhdHRlcm4gaW4gZ3JhZGUgZGlzdHJpYnV0aW9uIGJ5IGJvcm91Z2gsIGhvd2V2ZXIsIHRoZSBwbG90IHNob3dzIHVzIHRoYXQgZ3JhZGUgZGlzdHJpYnV0aW9ucyBhcmUgYWxtb3N0IHRoZSBzYW1lIHJlZ2FyZGxlc3Mgb2YgYm9yb3VnaC4KCmBgYHtyLGZpZy53aWR0aD04fQoKaW5zcGVjdGlvbl9ncmFkZXNfeWVhcjwtaW5zcGVjdGlvbl9ncmFkZXMlPiUgbXV0YXRlKHllYXI9ZmFjdG9yKGFzLm51bWVyaWMoZm9ybWF0KElOU1BFQ1RJT04uREFURSAsICclWScpKSkpCmluc3BlY3Rpb25fZ3JhZGVzX3llYXI8LWluc3BlY3Rpb25fZ3JhZGVzX3llYXIlPiUgc2VsZWN0KC1JTlNQRUNUSU9OLkRBVEUpCiBpbnNwZWN0aW9uX2dyYWRlc195ZWFyIDwtIGluc3BlY3Rpb25fZ3JhZGVzX3llYXIgJT4lIGdhdGhlcihrZXksIHZhbHVlLCAtQk9STywteWVhcikgJT4lIGdyb3VwX2J5KEJPUk8seWVhciwga2V5LCB2YWx1ZSkgJT4lIAogICB0YWxseSAlPiUgc3ByZWFkKHZhbHVlLCBuLCBmaWxsID0gMCkjICU+JSBnYXRoZXIoYmxhaCwgLUJPUk8sIC1rZXkpICNzdW1tYXJpemUoYXByb3AgPSBBLyhBK0IrQyspKQpuYW1lcyhpbnNwZWN0aW9uX2dyYWRlc195ZWFyKVtuYW1lcyhpbnNwZWN0aW9uX2dyYWRlc195ZWFyKT09ImtleSJdIDwtICJncmFkZSIKbmFtZXMoaW5zcGVjdGlvbl9ncmFkZXNfeWVhcilbbmFtZXMoaW5zcGVjdGlvbl9ncmFkZXNfeWVhcik9PSIiXSA8LSAidW5rbm93biIKaW5zcGVjdGlvbl9ncmFkZXNfeWVhciA8LSBpbnNwZWN0aW9uX2dyYWRlc195ZWFyICU+JSBnYXRoZXIoa2V5LCB2YWx1ZSwgLUJPUk8sLWdyYWRlLC15ZWFyKQpSZWxGcmVxPC1mdW5jdGlvbihtKXsKICAgKChtICkvc3VtKG0pKQogfQppbnNwZWN0aW9uX2dyYWRlc195ZWFyPC1pbnNwZWN0aW9uX2dyYWRlc195ZWFyICU+JSBncm91cF9ieShCT1JPLGdyYWRlLHllYXIpICU+JQogICAgbXV0YXRlKHBlcmNlbnRhZ2UgPSAodmFsdWUvc3VtKHZhbHVlKSkqMTAwKQpnZ3Bsb3QoaW5zcGVjdGlvbl9ncmFkZXNfeWVhciwgYWVzKEJPUk8sIHBlcmNlbnRhZ2UgLGZpbGw9IGtleSkpICsgCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICtmYWNldF93cmFwKH55ZWFyLG5yb3c9MixuY29sPTMpKwogIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZT0iR3JhZGUiKSkrCiAgZ2d0aXRsZSgiJUdyYWRlIGRpc3RyaWJ1dGlvbiBieSBCT1JPVUdIIikKCmBgYAoKQWRkaW5nIHllYXIgdG8gdGhpcyBhbmFseXNpcyBzaG93ZWQgdXMgYW4gaW5jcmVhc2UgaW4gdGhlIHByb3BvcnRpYW4gb2YgQXMgaW4gU2F0YXRlbiBJc2xhbmQgaW4gMjAxNSBidXQgc2VlbWVkIGNvbnNpc3RlbnQgdGhyb3VnaG91dCB0aGUgcmVzdCBvZiB0aGUgcGxvdC4KCgpXZSBkZWNpZGVkIHRoYXQgYm9yb3VnaCBtYXkgYmUgdG9vIGdlbmVyYWwgYW5kIHRodXMgbG9va2VkIGF0IGdyYWRlIGRpc3RyaWJ1dGlvbiBieSB6aXAgY29kZSBhY3Jvc3MgdGhlIHZhcmlvdXMgeWVhcnMuIFdlIHVzZWQgYSBoZWF0IG1hcCB0byBkbyBzby4KYGBge3IsZmlnLmhlaWdodD0xMH0KbGlicmFyeSh2aXJpZGlzKQpub25ZZWFyRGF0YUZvckhlYXRNYXA8LVZpb2xhdGlvbnNEYXRhICU+JSBzZWxlY3QoR1JBREUsWklQQ09ERSkKI25vblllYXJEYXRhRm9ySGVhdE1hcDwtbm9uWWVhckRhdGFGb3JIZWF0TWFwJT4lbXV0YXRlKGdyYWRlWWVhcj1hcy5udW1lcmljKGZvcm1hdChHUkFERS5EQVRFICwgJyVZJykpKQpub25ZZWFyRGF0YUZvckhlYXRNYXAgPC0gbm9uWWVhckRhdGFGb3JIZWF0TWFwICU+JSBncm91cF9ieShHUkFERSxaSVBDT0RFKSAlPiUgdGFsbHkgClJlbEZyZXE8LWZ1bmN0aW9uKG0pewogICAoKG0gKS9zdW0obSkpCn0KCm5vblllYXJEYXRhRm9ySGVhdE1hcDwtICBub25ZZWFyRGF0YUZvckhlYXRNYXAgJT4lIGdyb3VwX2J5KFpJUENPREUpJT4lCiAgICBtdXRhdGUocGVyY2VudGFnZSA9IChuL3N1bShuKSkqMTAwKQoKZ2dwbG90KG5vblllYXJEYXRhRm9ySGVhdE1hcCwgYWVzKEdSQURFLCAKICAgICAgICAgICAgICAgICAgICAgICAgWklQQ09ERSwgZmlsbCA9IHBlcmNlbnRhZ2UpKSArCiAgZ2VvbV90aWxlKCkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpcygpICsKICAjZmFjZXRfd3JhcCh+Qk9STykKICBnZ3RpdGxlKCJQZXJjZW50YWdlIGdyYWRlIGRpc3RyaWJ1dGlvbiBieSB6aXBjb2RlIGFjcm9zcyB5ZWFyc1xuICIpKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT0tNDUsIGhqdXN0PS4xKSwKICAgICAgICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChtYXJnaW49bWFyZ2luKGI9LjUpLCBzaXplID0gMTUpKSt5bGFiKCJHcmFkZSIpCgoKYGBgCkRJU0NVU1MgV0lUSCBMQUtTSFlBCgpUaGUgbmV4dCBwYXJ0IG9mIG91ciBhbmFseXNpcyB3YXMgdG8gbG9vayBhdCB0aGUgYXZlcmFnZSBzY29yZXMgb2YgZWFjaCBjdWlzaW5lLiBXaXRoIHRoaXMgaW5mb3JtYXRpb24sIHdlIGNhbiBoZWxwIGNvbnN1bWVycyBzZWUgd2hhdCBraW5kcyBvZiBlc3RhYmxpc2htZW50cyBoYXZlIHRoZSBiZXN0IGFuZCB3b3JzdCBzY29yZXMgb24gYXZlcmFnZS4gVGhpcyBpbiB0ZXJtIGNhbiBoZWxwIGEgY29uc3VtZXIgY2hvb3NlIGEgdHlwZSBvZiBjdWlzaW5lIHdoZW4gdGhleSBhcmUgaHVuZ3J5LgoKYGBge3IsZmlnLmhlaWdodD0xMn0KYXZlcmFnZV9zY29yZXMgPC0gVmlvbGF0aW9uc0RhdGEgJT4lIHNlbGVjdCgtQ0FNSVMsIC1EQkEsIC1CVUlMRElORywgLVNUUkVFVCwgLVpJUENPREUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1QSE9ORSwgLUlOU1BFQ1RJT04uREFURSwgLUFDVElPTiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVZJT0xBVElPTi5DT0RFLCAtVklPTEFUSU9OLkRFU0NSSVBUSU9OLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtQ1JJVElDQUwuRkxBRywgLUdSQURFLCAtR1JBREUuREFURSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVJFQ09SRC5EQVRFLCAtSU5TUEVDVElPTi5UWVBFKQoKYXZlcmFnZV9jdWlzaW5lIDwtIGF2ZXJhZ2Vfc2NvcmVzICU+JSAgZ3JvdXBfYnkoQ1VJU0lORS5ERVNDUklQVElPTikgJT4lIG5hLm9taXQgJT4lCiAgc3VtbWFyaXplKGF2ZXJhZ2Vfc2NvcmUgPSBtZWFuKFNDT1JFKSkKYXZlcmFnZV9jdWlzaW5lIDwtIGFycmFuZ2UoYXZlcmFnZV9jdWlzaW5lLCAtYXZlcmFnZV9zY29yZSkKCmdncGxvdChhdmVyYWdlX2N1aXNpbmUsIGFlcyhyZW9yZGVyKHggPSBDVUlTSU5FLkRFU0NSSVBUSU9OLCAtLWF2ZXJhZ2Vfc2NvcmUpLCBhdmVyYWdlX3Njb3JlLCBmaWxsID0gQ1VJU0lORS5ERVNDUklQVElPTikpICsgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykrZ2d0aXRsZSgiQXZlcmFnZSBzY29yZSBhY3Jvc3MgY3Vpc2luZXMiKSt4bGFiKCJDdWlzaW5lIGRlc2NyaXB0aW9uIikreWxhYigiYXZlcmFnZSBzY29yZSIpK2dlb21fdGV4dChhZXMobGFiZWwgPSBzcHJpbnRmKCIlLjJmIiwgYXZlcmFnZV9zY29yZSkpLHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMC41LCBzaXplID0gMykKYGBgCgpgYGB7cn0Kd29yc3QxMCA8LSBhdmVyYWdlX2N1aXNpbmVbMToxMCxdCgpnZ3Bsb3Qod29yc3QxMCwgYWVzKHJlb3JkZXIoeCA9IENVSVNJTkUuREVTQ1JJUFRJT04sIC0tYXZlcmFnZV9zY29yZSksIGF2ZXJhZ2Vfc2NvcmUsIGZpbGwgPSBDVUlTSU5FLkRFU0NSSVBUSU9OKSkgKyBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpICsgY29vcmRfZmxpcCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnKStnZ3RpdGxlKCJBdmVyYWdlIHNjb3JlIG9mIFdvcnN0IDEwIGN1aXNpbmVzIikreGxhYigiQ3Vpc2luZSBkZXNjcmlwdGlvbiIpK3lsYWIoImF2ZXJhZ2Ugc2NvcmUiKStnZW9tX3RleHQoYWVzKGxhYmVsID0gc3ByaW50ZigiJS4yZiIsIGF2ZXJhZ2Vfc2NvcmUpKSxwb3NpdGlvbj1wb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpKQpgYGAKCmBgYHtyfQpuIDwtIG5yb3coYXZlcmFnZV9jdWlzaW5lKQpiZXN0MTAgPC0gYXZlcmFnZV9jdWlzaW5lWyhuLSAxMCk6bixdCmJlc3QxMCA8LSBiZXN0MTBbb3JkZXIoYmVzdDEwJGF2ZXJhZ2Vfc2NvcmUpLF0KCmdncGxvdChiZXN0MTAsIGFlcyhyZW9yZGVyKHggPSBDVUlTSU5FLkRFU0NSSVBUSU9OLCAtYXZlcmFnZV9zY29yZSksIGF2ZXJhZ2Vfc2NvcmUsIGZpbGwgPSBDVUlTSU5FLkRFU0NSSVBUSU9OKSkgKyBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpICsgY29vcmRfZmxpcCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnKStnZ3RpdGxlKCJBdmVyYWdlIHNjb3JlIG9mIHRvcCAxMCBjdWlzaW5lcyIpK3hsYWIoIkN1aXNpbmUgZGVzY3JpcHRpb24iKSt5bGFiKCJhdmVyYWdlIHNjb3JlIikrZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHNwcmludGYoIiUuMmYiLCBhdmVyYWdlX3Njb3JlKSkscG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLCNwb3NpdGlvbj1wb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMC41LCBzaXplID0gNCkKYGBgCgpJdCBpcyBpbnRlcmVzdGluZyB0aGF0IHRoZSBteXN0ZXJpb3VzICJub3QgYXBwbGljYWJsZSIiIGN1aXNpbmUgaXMgb25lIG9mIHRoZSBiZXN0IQoKSW4gdGhpcyBuZXh0IHBsb3QsIHdlIHdhbnRlZCB0byBzZWUgaWYgdGhlIGF2ZXJhZ2Ugc2NvcmUgc2lnbmlmaWNhbnRseSBkaWZmZXJlZCBieSBCb3JvdWdoCmBgYHtyfQphdmVyYWdlX2Jvcm91Z2ggPC0gYXZlcmFnZV9zY29yZXMgJT4lICBncm91cF9ieShCT1JPKSAlPiUgbmEub21pdCAlPiUKICBzdW1tYXJpemUoYXZlcmFnZV9zY29yZSA9IG1lYW4oU0NPUkUpKQoKZ2dwbG90KGF2ZXJhZ2VfYm9yb3VnaCwgYWVzKHJlb3JkZXIoeCA9IEJPUk8sIC0tYXZlcmFnZV9zY29yZSksIGF2ZXJhZ2Vfc2NvcmUsIGZpbGwgPSBCT1JPKSkgKyBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnKStnZ3RpdGxlKCJBdmVyYWdlIHNjb3JlIGFjcm9zcyBib3JvdWdocyIpK3hsYWIoIkJvcm91Z2giKSt5bGFiKCJhdmVyYWdlIHNjb3JlIikrZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHNwcmludGYoIiUuMmYiLCBhdmVyYWdlX3Njb3JlKSkscG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdCA9IC0wLjUsIHNpemUgPSAzKQpgYGAKCkFsdGhvdWdoIHdlIHNlZSBzbGlnaHQgZGlmZmVyZW5jZSwgdGhlIGJvcm91Z2hzIGhhdmUgYXBwcm94aW1hdGVseSB0aGUgc2FtZSBhdmVyYWdlIHNjb3JlLiBTdGF0ZW4gSXNsYW5kIG1heSBiZSB0aGUgb25lIGV4Y2VwdGlvbi4gV2UgYWxzbyBmYWNldGVkIGJ5IHllYXIgdG8gc2VlIGlmIHRoYXQgbWFkZSBhIGRpZmZlcmVuY2UsIGJ1dCB0aGUgcmVzdWx0cyB3ZXJlIGVzc2VudGlhbGx5IHRoZSBzYW1lIGFzIGluIHRoZSBwbG90IGFib3ZlLgoKU28gZmFyIHdlIGxvb2tlZCBhdCBncmFkZXMgYW5kIHNjb3JlcyBidXQgbm90IHRoZSBhY3R1YWwgdmlvbGF0aW9ucy4gV2hhcmUgYXJlIHRoZSB0b3AgdmlvbGF0aW9ucyByZXN0YXVyYW50cyB1c3VhbGx5IGZhY2U/CmBgYHtyLGZpZy53aWR0aD0xMn0KCnZpb2xhdGlvbnM8LSBWaW9sYXRpb25zRGF0YSAlPiUgc2VsZWN0KC1DQU1JUywgLURCQSwgLUJVSUxESU5HLCAtU1RSRUVULCAtWklQQ09ERSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVBIT05FLCAtSU5TUEVDVElPTi5EQVRFLCAtQUNUSU9OLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtVklPTEFUSU9OLkNPREUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1DUklUSUNBTC5GTEFHLCAtR1JBREUsIC1HUkFERS5EQVRFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtUkVDT1JELkRBVEUsIC1JTlNQRUNUSU9OLlRZUEUpCgp2cyA8LSB2aW9sYXRpb25zICU+JSAgZ3JvdXBfYnkoVklPTEFUSU9OLkRFU0NSSVBUSU9OKSAlPiUgbmEub21pdCAlPiUKICBzdW1tYXJpemUoY291bnQgPSBuKCkpCnZzIDwtIGFycmFuZ2UodnMsIC1jb3VudCkKCnRvcHZpb2xhdGlvbnMgPC0gdnNbMToxMCxdCgpsaWJyYXJ5KHN0cmluZ3IpCnRvcHZpb2xhdGlvbnMkdmlvbCA9IHN0cl93cmFwKHRvcHZpb2xhdGlvbnMkVklPTEFUSU9OLkRFU0NSSVBUSU9OLCB3aWR0aCA9IDE1KQoKZ2dwbG90KHRvcHZpb2xhdGlvbnMsIGFlcyhyZW9yZGVyKHZpb2wsIC1jb3VudCksIGNvdW50LGZpbGw9dmlvbCkpICsgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykrZ2d0aXRsZSgiVG9wIDEwIHZpb2xhdGlvbnMiKSt4bGFiKCJWaW9sYXRpb24gZGVzY3JpcHRpb24iKSt5bGFiKCJjb3VudCIpK2dlb21fdGV4dChhZXMobGFiZWwgPSBzcHJpbnRmKCIlLjBmIiwgY291bnQpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdCA9IC0wLjUsIHNpemUgPSA3KQpgYGAKCldlIGFsc28gaHlwb3RoZXNpemVkIHRoYXQgdGhlIHR5cGUgb2YgaW5zcGVjdGlvbnMgd291bGQgZ2VuZXJhbGx5IHZhcnkgYnkgQm9yb3VnaCBidXQgZXZlbiB0aGlzIHdhcyBtb3N0bHkgY29uc2lzdGVudC4KYGBge3IsZmlnLmhlaWdodD02fQogbGlicmFyeSh2aXJpZGlzKQptb3M8LSBWaW9sYXRpb25zRGF0YSAlPiUgc2VsZWN0KC1DQU1JUywgLURCQSwgLUJVSUxESU5HLCAtU1RSRUVULCAtWklQQ09ERSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtUEhPTkUsIC1BQ1RJT04sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVZJT0xBVElPTi5DT0RFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1DUklUSUNBTC5GTEFHLCAtR1JBREUsIC1HUkFERS5EQVRFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1SRUNPUkQuREFURSwgLVNDT1JFLCAtQ1VJU0lORS5ERVNDUklQVElPTiwgLVZJT0xBVElPTi5ERVNDUklQVElPTikKbW9zJHllYXIgPC0gZmFjdG9yKGFzLm51bWVyaWMoIGZvcm1hdChtb3MkSU5TUEVDVElPTi5EQVRFICwgJyVZJykpKQptb3MgPC0gbW9zICU+JSBzZWxlY3QoLUlOU1BFQ1RJT04uREFURSkKCmF2ZXJhZ2VfbW9zIDwtIG1vcyAlPiUgZ3JvdXBfYnkoQk9STywgeWVhciwgSU5TUEVDVElPTi5UWVBFKSAlPiUgdGFsbHkgJT4lCiBncm91cF9ieShCT1JPLCB5ZWFyKSAgJT4lIAogbXV0YXRlKHAgPSBuIC8gc3VtKG4pKQojYXZlcmFnZV9jdWlzaW5lIDwtIGFycmFuZ2UoYXZlcmFnZV9jdWlzaW5lLCAtYXZlcmFnZV9zY29yZSkKCmxpYnJhcnkodmNkKQphdmVyYWdlX21vcyA8LSBhdmVyYWdlX21vcyAlPiUgc2VsZWN0KC1uKQoKCmdncGxvdChhdmVyYWdlX21vcywgYWVzKEJPUk8sIAogICAgICAgICAgICAgICAgICAgICAgIElOU1BFQ1RJT04uVFlQRSwgZmlsbCA9IHApKSArCiBnZW9tX3RpbGUoKSArCiBzY2FsZV9maWxsX3ZpcmlkaXMoKSArCiAjZmFjZXRfd3JhcCh+Qk9STykKIGdndGl0bGUoIkFWRVJBR0UgVklPTEFUSU9OIFNDT1JFIEJZIFpJUCBDT0RFXG4gIikrCiB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9LTQ1LCBoanVzdD0uMSksCiAgICAgICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChtYXJnaW49bWFyZ2luKGI9LjUpLCBzaXplID0gMTUpKStndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9InBlcmNlbnRhZ2UiKSkKCmBgYApPbmUgdGhpbmcgd2Ugbm90aWNlZCB3YXMgdGhhdCBTdGF0ZW4gaXNsYW5kIGhhcyB0aGUgbW9zdCBDeWNsZSBJbnNwZWN0aW9uL0luaXRpYWwgSW5zcGVjdGlvbi4gTWF5YmUgdGhleSB3ZXJlIG9wZW5pbmcgdXAgbWFueSBuZXcgcmVzdHVhcmFudHMuCgoKT25lIGZhY3RvciBvZiBvdXIgZGF0YSBzZXQgd2UgaGF2ZW4ndCBkaXNjdXNzZWQgdG9vIG11Y2ggaXMgdGhlIENyaXRpY2FsIGZsYWcsIHNheWluZyB3aGV0aGVyIG9yIG5vdCBhIHZpb2xhdGlvbiBpcyBjcml0aWNhbC4gT25jZSBhZ2Fpbiwgd2UgYXNzdW1lZCB0aGF0IG92ZXIgdGhlIHllYXJzIGFuZCBhY3Jvc3MgZGlmZmVyZW50IGJvcm91Z2hzLCB0aGVyZSB3b3VsZCBiZSBzb21lIHBhdHRlcm4gaW4gY3JpdGljYWwgdmlvbGF0aW9ucy4gQXMgY2FuIGJlIGluZmVycmVkIGZyb20gdGhlIGZvbGxvd2luZyBwbG90LCB0aGVyZSBpcyBub3QuCmBgYHtyLGZpZy53aWR0aD01fQpDcml0aWNhbGl0eURhdGE8LSBWaW9sYXRpb25zRGF0YSAlPiUgc2VsZWN0KEJPUk8sSU5TUEVDVElPTi5EQVRFLENSSVRJQ0FMLkZMQUcpICU+JSBuYS5vbWl0KCkKQ3JpdGljYWxpdHlEYXRhJHllYXI8LWZhY3Rvcihhcy5udW1lcmljKCBmb3JtYXQoQ3JpdGljYWxpdHlEYXRhJElOU1BFQ1RJT04uREFURSAsICclWScpKSkKI0NyaXRpY2FsaXR5RGF0YSA8LSBDcml0aWNhbGl0eURhdGEgJT4lc2VsZWN0KC1JTlNQRUNUSU9OLkRBVEUpCgpDcml0aWNhbGl0eURhdGEgPC0gQ3JpdGljYWxpdHlEYXRhICU+JXNlbGVjdCgtSU5TUEVDVElPTi5EQVRFKSAlPiVnYXRoZXIoa2V5LCB2YWx1ZSwgLUJPUk8sIC15ZWFyKSAlPiUgZ3JvdXBfYnkoQk9STywgeWVhcixrZXksdmFsdWUpICU+JXRhbGx5ICU+JSBzcHJlYWQodmFsdWUsIG4sIGZpbGwgPSAwKQpuYW1lcyhDcml0aWNhbGl0eURhdGEpWzVdIDwtICJOb3RBcHBsaWNhYmxlIgpuYW1lcyhDcml0aWNhbGl0eURhdGEpWzZdIDwtICJOb25Dcml0aWNhbCIKCkNyaXRpY2FsaXR5RGF0YVBlcmNlbnRhZ2U8LUNyaXRpY2FsaXR5RGF0YSAlPiUgc3VtbWFyaXplKGNyaXRpY2FsUGVyY2VudCA9IENyaXRpY2FsLyhDcml0aWNhbCtOb3RBcHBsaWNhYmxlK05vbkNyaXRpY2FsKSwgTm90QXBwbGljYWJsZVBlcmNlbnQgPSBOb3RBcHBsaWNhYmxlLyhDcml0aWNhbCtOb3RBcHBsaWNhYmxlK05vbkNyaXRpY2FsKSwgTm9uQ3JpdGljYWxQZXJjZW50ID0gTm9uQ3JpdGljYWwvKENyaXRpY2FsK05vdEFwcGxpY2FibGUrTm9uQ3JpdGljYWwpKSMKCm5hbWVzKENyaXRpY2FsaXR5RGF0YVBlcmNlbnRhZ2UpWzRdIDwtICJDcml0aWNhbCIKbmFtZXMoQ3JpdGljYWxpdHlEYXRhUGVyY2VudGFnZSlbNV0gPC0gIk5vdEFwcGxpY2FibGUiCm5hbWVzKENyaXRpY2FsaXR5RGF0YVBlcmNlbnRhZ2UpWzZdIDwtICJOb25Dcml0aWNhbCIKQ3JpdGljYWxpdHlEYXRhUGVyY2VudGFnZTwtQ3JpdGljYWxpdHlEYXRhUGVyY2VudGFnZSU+JSBnYXRoZXIoa2V5MSwgdmFsdWUsIC1CT1JPLCAteWVhciwta2V5KQoKCmdncGxvdChDcml0aWNhbGl0eURhdGFQZXJjZW50YWdlLCBhZXMoQk9STywgdmFsdWUsIGZpbGwgPSBrZXkxKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKyAKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiKSsgeGxhYigiQk9ST1VHSCIpK3lsYWIoIkNSSVRJQ0FMSVRZIFBFUkNFTlRBR0VTIikgK3RoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpKyBnZ3RpdGxlKCJHcm91cGVkIGJhcmNoYXJ0IG9mIGdyYWRlIGZyZXF1ZW5jeSBpbiBlYWNoIGN1aXNpbmUgY2F0ZWdvcnkgXG4gd2hlbiB0aGVyZSB3YXMgYSB2aW9sYXRpb24gcmVwb3J0ZWQiKStmYWNldF93cmFwKH55ZWFyLG5yb3c9MixuY29sPTMpK2d1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZT0iQ3JpdGljYWxpdHkgXG4gY2F0ZWdvcnkiKSkKCmBgYApXZSBhdHRlbXB0ZWQgdG8gZnVydGhlciBhbmFseXplIHRoZSBjcml0aWNhbCBmbGFnIGJ1dCB3ZSBsZWFybmVkIHRoYXQgdGhlIGNyaXRpY2FsIGZsYWcgZGlkIG5vdCBoYXZlIHRvbyBtdWNoIGltcGFjdCBvbiBncmFkZSBvciBzY29yZXMuIFRoZXJlIHdhcyBhIGxvdCBvZiBkYXRhIHdpdGggYSBncmFkZSBvZiBBIGJ1dCBhIENyaXRpY2FsIGZsYWcgd2hpbGUgb3RoZXJzIHdpdGggYSB2ZXJ5IGhpZ2ggc2NvcmUgYnkgbm8gY3JpdGljYWwgZmxhZy4KCkZvciB0aGUgcmVtYWluZGVyIG9mIHRoZSBhbmFseXNpcywgd2Ugd2lsbCBiZSB3b3JraW5nIHdpdGggVGFibGVhdS4gV2UgY2hvc2UgVGFibGVhdSBiZWNhdXNlIHdlIHdhbnRlZCB0byBwbG90IGVsZWdlbnQgbWFwcy4gVGFibGVhdSBwcm92aWRlcyBhIHNpbXBsZXIgYW5kIG1vcmUgZWxlZ2VudCB3YXkgdG8gZG8gc28gdGhhbiBpbiBSLgoKVGhlIGNvZGUgY2h1bmtzIHdpbGwgZ2VuZXJhdGUgdGhlIGRhdGEgdGhhdCB3ZSB1cGxvYWQgdG8gVGFibGVhdS4gSW4gdGhlIGZvbGxvd2luZyBhbmFseXNpcywgd2UgZXhwbG9yZSB0aGUgcHJvcG9ydGlvbiBvZiBBIGdyYWRlcyBiYXNlZCBvbiBuZWlnaGJvcmhvb2Qgb3ZlciB0aGUgeWVhcnMuCmBgYHtyLGZpZy5oZWlnaHQ9MTV9CiMjIyMjR0VORVJBVEUgR1JBREUgUFJPUE9FUlRJT04gREFUQVNFVCBCWSBZRUFSIEZPUiBUQUJMRUFVIFBMT1RUSU5HCnppcGRhdGE8LSBWaW9sYXRpb25zRGF0YSAlPiUgc2VsZWN0KC1DQU1JUywgLURCQSwgLUJVSUxESU5HLCAtU1RSRUVULCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtUEhPTkUsIC1BQ1RJT04sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1WSU9MQVRJT04uQ09ERSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLUNSSVRJQ0FMLkZMQUcsIC1TQ09SRSwgLUdSQURFLkRBVEUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1SRUNPUkQuREFURSwgLUlOU1BFQ1RJT04uVFlQRSwgLVZJT0xBVElPTi5ERVNDUklQVElPTiwgLUNVSVNJTkUuREVTQ1JJUFRJT04sIC1CT1JPKSAlPiUgbmEub21pdCgpCnppcGRhdGEkeWVhcjwtZmFjdG9yKGFzLm51bWVyaWMoIGZvcm1hdCh6aXBkYXRhJElOU1BFQ1RJT04uREFURSAsICclWScpKSkKemlwZGF0YUdyYWRlUGVyY2VudGFnZSA8LSB6aXBkYXRhICU+JXNlbGVjdCgtSU5TUEVDVElPTi5EQVRFKSAlPiVnYXRoZXIoa2V5LCB2YWx1ZSwgLVpJUENPREUsIC15ZWFyKSAlPiUgZ3JvdXBfYnkoWklQQ09ERSwgeWVhciwga2V5LCB2YWx1ZSkgJT4lCiAgdGFsbHkgJT4lIHNwcmVhZCh2YWx1ZSwgbiwgZmlsbCA9IDApICU+JSBzdW1tYXJpemUoYXByb3AgPSBBLyhBK0IrQyksIGJwcm9wID0gQi8oQStCK0MpLCBjcHJvcCA9IEMvKEErQitDKSApCgojIGdncGxvdCh6aXBkYXRhR3JhZGVQZXJjZW50YWdlLCBhZXMocmVvcmRlcih4ID0gWklQQ09ERSwgLS1hcHJvcCksIGFwcm9wKSkgKyBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpICsgCiMgICBjb29yZF9mbGlwKCkgKyBmYWNldF93cmFwKH55ZWFyKQojICAgdGhlbWUoIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMykpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBcHJvcDEucG5nJykKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0Fwcm9wMi5wbmcnKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXByb3AzLnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBcHJvcDQucG5nJykKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0Fwcm9wNS5wbmcnKQpgYGAKCk92ZXIgdGhlIHllYXJzLCB0aGUgcHJvcG9ydGlvbiBvZiBBJ3MgaGFzIGluY3JlYXNlZCwgYXMgcmVwcmVzZW50ZWQgYnkgdGhlIGRhcmtlciByZWQgc2hhZGluZyBvZiB0aGUgbWFwLiBJdCBpcyB0b28gZWFybHkgdG8gc3R1ZHkgMjAxNyBpbiBkZXB0aCBkdWUgdG8gdGhlIGxpbWl0ZWQgbnVtYmVyIG9mIGluc3BlY3Rpb25zIHNvIGZhci4KCkxldCdzIGxvb2sgYXQgaG93IHRoZSBwcm9wb3J0aW9uIG9mIEIncyBjaGFuZ2UuCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0Jwcm9wMS5wbmcnKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQnByb3AyLnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdCcHJvcDMucG5nJykKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0Jwcm9wNC5wbmcnKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQnByb3A1LnBuZycpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IG92ZXIgdGhlIHllYXJzLCB0aGVyZSBzZWVtIHRvIGJlIGxlc3MgQidzIHdoaWNoIG1ha2VzIHNlbnNlIHNpbmNlIG92ZXIgdGhlIHllYXJzIHdlIGhhdmUgbW9yZSBncmFkZXMgb2YgQS4KCkxldCdzIGxvb2sgYXQgdGhlIGF2ZXJhZ2Ugc2NvcmVzIGJ5IG5laWdoYm9yaG9vZC4gV2UgaGF2ZSBhbHJlYWR5IGRvbmUgc28gYnkgY3Vpc2luZS4KCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXZnVmlvbFNjb3JlQnlaaXAyMDEzLnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBdmdWaW9sU2NvcmVCeVppcDIwMTQucG5nJykKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0F2Z1Zpb2xTY29yZUJ5WmlwMjAxNS5wbmcnKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXZnVmlvbFNjb3JlQnlaaXAyMDE2LnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBdmdWaW9sU2NvcmVCeVppcDIwMTcucG5nJykKYGBgCgpPdmVyIHRoZSB5ZWFycywgd2UgaGF2ZSBhIGxvd2VyIEF2ZXJhZ2UgU2NvcmUuIFRoZXNlIE5ZQyBpbnNwZWN0aW9ucyBtdXN0IGJlIHByb21wdGluZyByZXN0dXJhbnRzIHRvIGltcHJvdmUgdGhlaXIgZmFjaWxpdGllcyBhbmQgZm9sbG93IHJlZ3VsYXRpb25zIQoKV2UgZGVjaWRlZCB0byBzZWUgd2hpY2ggYXJlYXMgaGFkIHRoZSBoaWdoZXN0IGF2ZXJhZ2UgbnVtYmVyIG9mIHJlaW5zcGVjdGlvbnMuIE1heWJlIHRoaXMgY2FuIGV4cGxhaW4gdGhlIGJldHRlciBzY29yZXMgYW5kIGdyYWRlcyBvdmVyIHRpbWUuCgpgYGB7cn0KIyMjIERBVEEgR0VORVJBVElPTgpsaWJyYXJ5KHN0cmluZ3IpCnJlaW5zcGVjdCA8LSBWaW9sYXRpb25zRGF0YSAlPiUgc2VsZWN0KC1DQU1JUywgLURCQSwgLUJVSUxESU5HLCAtU1RSRUVULCAtQ1VJU0lORS5ERVNDUklQVElPTiwgLUJPUk8sIC1TQ09SRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1QSE9ORSwgSU5TUEVDVElPTi5EQVRFLCAtQUNUSU9OLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1WSU9MQVRJT04uQ09ERSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtQ1JJVElDQUwuRkxBRywgLUdSQURFLCAtR1JBREUuREFURSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtUkVDT1JELkRBVEUpCnJlaW5zcGVjdCR5ZWFyPC1mYWN0b3IoYXMubnVtZXJpYyggZm9ybWF0KHJlaW5zcGVjdCRJTlNQRUNUSU9OLkRBVEUgLCAnJVknKSkpCgojaW5zcGVjdGlvbl90eXBlcyA8LSBJTlNQRUNUSU9OLlRZUEUKcmVpbnNwZWN0IDwtIHJlaW5zcGVjdCAlPiVzZWxlY3QoLUlOU1BFQ1RJT04uREFURSkgICU+JSBuYS5vbWl0ICU+JSBmaWx0ZXIoc3RyX2RldGVjdChJTlNQRUNUSU9OLlRZUEUsICJSZS1pbnNwZWN0aW9uIikpJT4lZ3JvdXBfYnkoVklPTEFUSU9OLkRFU0NSSVBUSU9OLCB5ZWFyLCBaSVBDT0RFICkgICU+JSB0YWxseSMgc3VtbWFyaXNlKHJlID0gc3VtKHN0cl9jb3VudChyZWluc3BlY3QkSU5TUEVDVElPTi5UWVBFLCAiUmUtaW5zcGVjdGlvbiIpKSkKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0F2Z1JlaW5zcGVjdDIwMTMucG5nJykKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0F2Z1JlaW5zcGVjdDIwMTQucG5nJykKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0F2Z1JlaW5zcGVjdDIwMTUucG5nJykKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0F2Z1JlaW5zcGVjdDIwMTYucG5nJykKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0F2Z1JlaW5zcGVjdDIwMTcucG5nJykKYGBgCgpJbnRlcmVzdGluZ2x5IGVub3VnaCwgdGhlIGFyZWFzIHdpdGggdGhlIG1vc3QgcmVpbnNwZWN0aW9ucyBzZWVtIHRvIGJlIHRoZSBvbmVzIGluIHdoaWNoIHRoZSBncmFkZXMgYW5kIHNjb3JlcyBpbXByb3ZlZC4gVGhlIHN5c3RlbSBvZiByZWluc3BlY3Rpb25zIG11c3QgYmUgd29ya2luZyEKCgpBcyBhIGxhc3QgYml0IG9mIGFuYWx5c2lzLCB3ZSBkZWNpZGVkIHRvIGhlbHAgc2V0dGxlIGEgaHVnZSBkaWxlbW5hIDogV2hlcmUgc2hvdWxkIHlvdSBnZXQgeW91ciBjb2ZmZWUsIFN0YXJidWNrcyBvciBEdW5raW5nIERvbnV0cz8KCmBgYHtyfQojI0RBVEEgR0VORVJBVElPTiBDT0RFCmxpYnJhcnkoc3RyaW5ncikKQ2hhaW5zc0RmPC1WaW9sYXRpb25zRGF0YSU+JSBtdXRhdGUoaXNTdGFyYnVja3M9c3RyX2RldGVjdChEQkEsIlNUQVJCVUNLIikpICU+JSBtdXRhdGUoaXNEdW5raW49c3RyX2RldGVjdChEQkEsIkRVTktJTiIpKQpDaGFpbnNzRGYkREJBW0NoYWluc3NEZiRpc1N0YXJidWNrcz09VFJVRV08LSJTVEFSQlVDS1MiCkNoYWluc3NEZiREQkFbQ2hhaW5zc0RmJGlzRHVua2luPT1UUlVFXTwtIkRVTktJTiIKQ2hhaW5zc0RmPC1DaGFpbnNzRGYlPiVmaWx0ZXIoREJBICVpbiUgYygiU1RBUkJVQ0tTIiwiRFVOS0lOIikpCkNoYWluc3NEZjwtQ2hhaW5zc0RmJT4lc2VsZWN0KERCQSxCT1JPLElOU1BFQ1RJT04uREFURSxaSVBDT0RFLFNDT1JFLFZJT0xBVElPTi5ERVNDUklQVElPTixHUkFERSkKQ2hhaW5zc0RmJHllYXI8LWZhY3Rvcihhcy5udW1lcmljKCBmb3JtYXQoQ2hhaW5zc0RmJElOU1BFQ1RJT04uREFURSAsICclWScpKSkKQ2hhaW5zc0RmPC1DaGFpbnNzRGYlPiVzZWxlY3QoLUlOU1BFQ1RJT04uREFURSkKYGBgCgpBcyB5b3UgY2FuIHNlZSwgRHVua2luZyBEb251dHMgaGFzIG1vcmUgY3JpdGljYWwgdmlvbGF0aW9ucyB0aGFuIFN0YXJidWNrcyBpbiBldmVyeSBCb3JvdWdoLiBOb3RpY2libGUgZGlmZmVyZW5jZXMgYXJlIGVzcGVjaWFsbHkgc2VlIGluIEJyb29rbHluIGFuZCBNYW5oYXR0YW4uCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnRFMxLnBuZycpCmBgYAoKCkJvdGggZXN0YWJsaXNobWVudHMgc2hhcmVkIHRoZSBzYW1lIHRvcCB2aW9sYXRpb25zLiBMZXQncyBzZWUgd2hhdCBwZXJjZW50YWdlIG9mIHRoZXNlIHZpb2xhdGlvbnMgZWFjaCBoYXMuIApgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0RTMi5wbmcnKQpgYGAKT25jZSBhZ2FpbiwgU3RhcmJ1Y2tzIGlzIHRoZSB3aW5uZXIhCgpXaGF0IGFib3V0IHRoZSBhdmVyYWdlIHNjb3JlPwpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0RTMy5wbmcnKQpgYGAKClJlZ2FyZGxlcyBvZiB0aGUgeWVhciwgdGhlIGF2ZXJhZ2Ugc2NvcmUgb2YgRHVua2luZyBEb251dHMgaGFzIGJlZW4gaGlnaGVyLiBUaGUgaGlnaGVyIHRoZSBzY29yZSwgdGhlIHdvcnNlLiBOb3RpY2libGUgZGlmZmVyZW5jZXMgYXJlIHNlZW4gaW4gMjAxNSBhbmQgdGhlIGZpcnN0IHRocmVlIG1vbnRocyBvZiAyMDE3LgoKTGV0J3Mgc2VlIGlmIHRoZSBCb3JvdWdoIHlvdXIgaW4gc2hvdWxkIGltcGFjdCB5b3VyIGNob2ljZS4KYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdEUzQucG5nJykKYGBgCgpJIGd1ZXNzIHdoZW4geW91J3JlIGluIEJyb29rbHluLCBpdCBkb2Vzbid0IG1hdHRlciBidXQgZXZlcnl3aGVyZSBlbHNlLCBzdGljayB0aGUgU3RhcmJ1Y2tzLCBlc3BlY2lhbGx5IHlvdSBTdGF0ZW4gSXNsYW5kIGZvbGtzIQoKIyMgQ29uY2x1c2lvbgpNYW55IGxpbWl0YXRpb25zIGluY2x1ZGVkIHRoZSBtaXNzaW5nIGRhdGEgaXRzZWxmLiBXZSBsZWFybmVkIHRoYXQgc29tZXRpbWVzLCB3aGF0IG1heSBzZWVtIGxpa2UgYW4gaW50dWl0aXZlIGh5cG90aGVzaXMsIGlzIGFjdHVhbGx5IGNvbXBsZXRlbHkgZmFsc2UuIFRoZXJlIHdlcmUgbm90IGFzIG1hbnkgcGF0dGVybnMgYXMgd2UgYW50aWNpcGF0ZWQgaW4gdGVybXMgb2YgQm9yb3VnaC4gVGhlIG9ubHkgdGhpbmcgd2UgZGlkIHNlZSBpcyB0aGF0IG92ZXIgdGltZSwgdGhlIHNjb3JlIGFuZCBncmFkZSBoYXMgaW5jcmVhc2VkLCBzaG93aW5nIHVzIHRoYXQgdGhlIGluc3BlY3Rpb25zIGFyZSB3b3JraW5nIGFuZCB0aGF0IHJlc3R1YXJhbnRzIGFyZSBpbXByb3ZpbmcgdGhlaXIgZmNpbGl0aWVzIHRvIHJlY2VpZXZlIGEgYmV0dGVyIHNjb3JlLiBBY2NvcmRpbmcgdG8gdGhlIHdlYnNpdGUgd2UgcmVjZXZlZCB0aGUgZGF0YSBmcm9tZSwgdGhyZWUgZmllbGRzIGFyZSBzb29uIHRvIGJlIGFkZGVkIGFzIGRhdGEgbG9naWMgYmVjb21lcyBhdmFpbGFibGUgdG8gcG9wdWxhdGUgdGhlbSBhY2N1cmF0ZWx5LiBUaG9zZSBmaWVsZHMgYXJlIFZJT0xBVElPTiBQT0lOVFMgKHRoZSBwb2ludHMgYXNzaWduZWQgdG8gYSB2aW9sYXRpb24gYmVmb3JlIG9yIGFmdGVyIGFkanVkaWNhdGlvbiwgZGVwZW5kaW5nIG9uIHdoZXRoZXIgYWRqdWRpY2F0aW9uIGhhcyBvY2N1cnJlZCksIEZJTkVTIFRPVEFMICh0aGUgZmluZSBhbW91bnQgYWZ0ZXIgYWRqdWRpY2F0aW9uKSwgYW5kIERFQ0lTSU9OIERBVEUgKGFkanVkaWNhdGlvbiBkYXRlIOKAkyBvciBkYXRlIGEgZ3JhZGUgYmVjb21lcyBmaW5hbCkuIFdpdGggdGhpcyBpbmZvcm1hdGlvbiwgd2UgY2FuIGRvIG1vcmUgYW5hbHlzaXMgdG8gc2VlIHRoZSBmaW5lcyBvZiB2YXJpb3VzIHZpb2xhdGlvbnMgYW5kIGxlYXJuIGhvdyBlYWNoIHZpb2xhdGlvbiBhY3R1YWxseSBhZmZlY3RzIHRoZSBzY29yZS4gV2l0aCB0aGF0LCByZXN0YXVyYW50cyBjYW4gZm9jdXMgb24gdGhlIG1haW4gdmlvbGF0aW9ucyB0byBpbXByb3ZlIHRoZWlyIHNjb3JlcyBpbiB0aGUgbmV4dCBpbnNwZWN0aW9uLgoKCgoKCg==